Retrofit是否在主线程上进行网络调用?

Jag*_*uar 31 android retrofit okhttp

我正在尝试在Android上探索Retrofit + OkHttp.这是我在网上找到的一些代码:

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

如果我不使用执行程序服务,我的代码是否会在主线程上运行?我应该在新线程中发出Web请求吗?

Jak*_*ton 116

可以为同步或异步执行声明Retrofit方法.

具有返回类型的方法将同步执行.

@GET("/user/{id}/photo")
Photo getUserPhoto(@Path("id") int id);
Run Code Online (Sandbox Code Playgroud)

异步执行需要方法的最后一个参数为a Callback.

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

在Android上,回调将在主线程上执行.对于桌面应用程序,回调将在执行HTTP请求的同一线程上发生.

Retrofit还集成了RxJava以支持返回类型为的方法 rx.Observable

@GET("/user/{id}/photo")
Observable<Photo> getUserPhoto(@Path("id") int id);
Run Code Online (Sandbox Code Playgroud)

可观察请求是异步订阅的,并在执行HTTP请求的同一线程上观察到.观察在不同的线程(例如Android的主线程)上调用observeOn(Scheduler)返回的Observable.

注意:RxJava集成是实验性的.

  • 正如它在答案中所述,如果你使用第二个模式(最后一个参数作为`Callback`),请求是异步完成的,但是在主线程上调用了回调.默认情况下,Retrofit会为这些请求使用线程池. (13认同)
  • 不,那是近两年前的事了. (5认同)
  • 在Retrofit 2上,我认为我们使用`call.enqueue()`来获得异步响应.我的问题是如何在不同的线程上调用,从工作线程上面调用`getUserPhoto()`方法? (3认同)
  • 谢谢你的答案,我想知道为什么它被投票了!无论如何,我的问题是网络代码是在幕后的一个单独的线程(或IntentService)上执行的(就像Volley一样); 或者我需要自己编写代码.您的回复是针对响应处理的...这也很有用:) (2认同)

Mar*_*res 16

返回值的方法是同步的.

@GET("/user/{id}/asset")
Asset getUserAsset(@Path("id") int id);
Run Code Online (Sandbox Code Playgroud)

要做到这一点异步你只需要添加一个回调.

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

希望这可以帮助.

问候!

  • -1:这不是问题的答案.我觉得@Jake Wharton在下面的答案更适合这个问题. (10认同)
  • 是的,对不起我在上次评论中回复.调用是在主线程上进行的. (2认同)

Ada*_*itz 10

Kotlin 协程

当使用suspend函数发出网络请求时,Retrofit 使用 CoroutineCallAdapter来分派工作线程。

因此,协程不需要在Dispatcher.IO线程上显式启动。

请参阅 Android 文档:来自网络和数据库的页面>实现 RemoteMediator

样本

注射.kt

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

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>
}
Run Code Online (Sandbox Code Playgroud)

Feed分页源

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) { ... }
    }
}
Run Code Online (Sandbox Code Playgroud)


Par*_*ani 9

复古2

众所周知,Retrofit 可以同步和异步执行请求。

同步方法在主线程上执行。这意味着 UI 在请求执行期间会阻塞,并且在此期间无法进行交互。

对于非阻塞 UI,您必须自己在单独的线程中处理请求执行。这意味着,您在等待响应时仍然可以与应用程序本身交互。

在Retrofit2中如果你想同步执行请求:

同步请求

public interface TaskService {  
  @GET("/tasks")
  Call<List<Task>> getTasks();
}
Run Code Online (Sandbox Code Playgroud)

从同步请求获取结果

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

Call<List<Task>> call = taskService.getTasks();  
List<Task>> tasks = call.execute().body();  
Run Code Online (Sandbox Code Playgroud)

但如果你想异步执行请求:

异步请求

public interface TaskService {  
  @GET("/tasks")
  Call<List<Task>> getTasks();
}
Run Code Online (Sandbox Code Playgroud)

从异步请求获取结果

//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());
 }
}
Run Code Online (Sandbox Code Playgroud)

上面已经提到: Retrofit 2 中的接口定义对于同步和异步请求是相同的。换句话说,在 Retrofit 2 中,每个请求都被包装到 Call 对象中。实际的同步或异步请求在稍后创建的调用对象上使用所需的方法以不同的方式执行。

  • 用于call.execute()同步运行。
  • 用于call.enqeue()异步运行。