43

I am trying to explore Retrofit+OkHttp on Android. Here's some code I found online :

RestAdapter restAdapter = new RestAdapter.Builder().setExecutors(executor, executor)
.setClient(new OkClient(okHttpClient))
.setServer("blah").toString())
.build();

If I don't use executor service, will my code be running on the main thread ? Should I make web requests in a new thread hence ?

dev
  • 11,071
  • 22
  • 74
  • 122

4 Answers4

136

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.

Jake Wharton
  • 75,598
  • 23
  • 223
  • 230
  • 2
    Thanks for the answer, I wonder why it was downvoted ! Anyways, my question was whether the network code is executed on a separate thread (or IntentService) behind the scenes (like Volley does); or do I need to write code for that by myself. Your response is targeting at the response processing... which is again useful :) – dev Jan 09 '14 at 02:22
  • 14
    As it states in the answer, if you use the second pattern (last argument as a `Callback`) the request is done asynchronously but the callback is invoked on the main thread. By default Retrofit uses a thread pool for these requests. – Jake Wharton Jan 09 '14 at 06:27
  • 3
    On Retrofit 2, i think we use `call.enqueue()` to get async response. My question is how to make call on different Thread, calling `getUserPhoto()`method above from worker Thread? – Jemshit Feb 17 '16 at 12:40
  • 1
    "Note: The RxJava integration is experimental." is this still true? – Marian Paździoch May 04 '16 at 11:27
  • 5
    No. That was from nearly 2.5 years ago. – Jake Wharton May 06 '16 at 00:54
18

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!

Martin Cazares
  • 13,637
  • 10
  • 47
  • 54
  • 1
    Thanks,I just wanted a confirmation if Retrofit is taking care of thread management as thee library is designed for network operations, and network ops should be done on a non-ui thread. – dev Jan 08 '14 at 21:36
  • Why don't you just try it? I think it worth it to just run the code and inmmediately you will notice if it's handled or not on main thread – Martin Cazares Jan 08 '14 at 21:38
  • 2
    Yeah, sorry for not replying in my last comment. The call is made on the main thread. – dev Jan 08 '14 at 21:46
  • 11
    -1: This isn't an answer to the question. I feel that @Jake Wharton's answer, below, is better suited to this question. – jwir3 Oct 07 '14 at 20:07
10

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) { ... }
    }
}
AdamHurwitz
  • 9,758
  • 10
  • 72
  • 134
9

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.
Parisa Baastani
  • 1,713
  • 14
  • 31
  • 1
    Thanks. I am working on an app using retrofit 2 and was wondering if I should create threads for network IO, but now I know I don't need to. – Joseph Sang Mar 17 '21 at 09:05