Does Retrofit make network calls on main thread?

The method that return a value does it Synchronously.

@GET("/user/{id}/asset")
Asset getUserAsset(@Path("id") int id);

To do it Asynchronous all you need is to add a Callback.

@GET("/user/{id}/asset")
void getUserAsset(@Path("id") int id, Callback<Asset> cb);

Hope this Helps.

Regards!


Retrofit methods can be declared for either synchronous or asynchronous execution.

A method with a return type will be executed synchronously.

@GET("/user/{id}/photo")
Photo getUserPhoto(@Path("id") int id);

Asynchronous execution requires the last parameter of the method be a Callback.

@GET("/user/{id}/photo")
void getUserPhoto(@Path("id") int id, Callback<Photo> cb);

On Android, callbacks will be executed on the main thread. For desktop applications callbacks will happen on the same thread that executed the HTTP request.

Retrofit also integrates RxJava to support methods with a return type of rx.Observable

@GET("/user/{id}/photo")
Observable<Photo> getUserPhoto(@Path("id") int id);

Observable requests are subscribed asynchronously and observed on the same thread that executed the HTTP request. To observe on a different thread (e.g. Android's main thread) call observeOn(Scheduler) on the returned Observable.

Note: The RxJava integration is experimental.


Retrofti 2

As you all might know, Retrofit can execute requests synchronously and Asynchronously.

Synchronous methods are executed on the main thread. That means the UI blocks during request execution and no interaction is possible for this period.

For non-blocking UI, you have to handle the request execution in a separated thread by yourself. That means, you can still interact with the app itself while waiting for the response.

In Retrofit2 if you want to execute requests synchronously:

Synchronous Requests

public interface TaskService {  
  @GET("/tasks")
  Call<List<Task>> getTasks();
}

Get Results from Synchronous Requests

//service generator
TaskService taskService = ServiceGenerator.createService(TaskService.class); 

Call<List<Task>> call = taskService.getTasks();  
List<Task>> tasks = call.execute().body();  

But if you want to execute the request asynchronously:

Asynchronous Requests

public interface TaskService {  
  @GET("/tasks")
  Call<List<Task>> getTasks();
}

Get Results from Asynchronous Requests

//service generator    
TaskService taskService = ServiceGenerator.createService(TaskService.class);  

Call<List<Task>> call = taskService.getTasks();  
call.enqueue(new Callback<List<Task>>() {  
  @Override
  public void onResponse(Call<List<Task>> call, Response<List<Task>> response) {
    if (response.isSuccessful()) {
        // tasks available
    } else {
        // error response, no access to resource?
    }
}

 @Override
 public void onFailure(Call<List<Task>> call, Throwable t) {
    // something went completely south (like no internet connection)
    Log.d("Error", t.getMessage());
 }
}

As already mentioned above: the interface definition in Retrofit 2 is the same for synchronous and asynchronous requests. In the other words within Retrofit 2, every request is wrapped into a Call object. The actual synchronous or asynchronous request is executed differently using the desired method on a later created call object.

  • Use call.execute() to run synchronously.
  • Use call.enqeue() to run asynchronously.

Kotlin Coroutines

When using a suspend function to make a network request, Retrofit uses a Coroutine CallAdapter to dispatch on a worker thread.

Therefore, a coroutine does not need to be explicitly launched on the Dispatcher.IO thread.

See Android documentation: Page from network and database > Implement a RemoteMediator

Sample

Injection.kt

object Injection {
    val feedService = Retrofit.Builder()
        .baseUrl(TWITTER_API_BASE_URL)
        .addConverterFactory(GsonConverterFactory.create())
        .build()
        .create(FeedService::class.java)
}

FeedService.kt

interface FeedService {
    // Retrofit makes the request on a background thread.
    @GET("lists/{listType}")
    suspend fun getTweets(
        @Path(LIST_TYPE_PATH) listType: String,
        @Query(LIST_ID_QUERY) listId: String,
        @Query(LIST_COUNT_QUERY) count: String,
        @Query(LIST_PAGE_NUM_QUERY) page: String
    ): List<Tweet>
}

FeedPagingSource

class FeedPagingSource : PagingSource<Int, Tweet>() {
    override suspend fun load(params: LoadParams<Int>): LoadResult<Int, Tweet> {
        try {
            // The results are returned on the main thread.
            val tweets: List<Tweet> = Injection.feedService.getTweets(...)
            return LoadResult.Page(...)
        } catch (error: Exception) { ... }
    }
}