美文网首页
Retrofit2线程切换

Retrofit2线程切换

作者: 机器大娃 | 来源:发表于2023-08-13 16:34 被阅读0次

    一、retrofit使用

    interface RequestService {
      @GET
      operator fun get(@Url url: String,@QueryMap params: HashMap<String, @JvmSuppressWildcards Any>): Call<String>
    }
    
    val client = Retrofit.Builder().apply {
       baseUrl("xxx")
       client(OkHttpHolder.okHttpClient)
    }.build()
    
    val service: RequestService = client.create(RequestService::class.java)
    val call: Call<String> = service.get("xxx",HashMap<String, String>())
    call.enqueue(object :Callback<String>{
                  override fun onResponse(call: Call<String>, response: Response<String>) {
                  }
                  override fun onFailure(call: Call<String>, t: Throwable) {
                  }
              })
    

    二、DefaultCallAdapterFactory.ExecutorCallbackCall

    service.get("xxx",HashMap<String, String>())
    

    通过源码可知,在调用get时,通过代理,会得到DefaultCallAdapterFactory.ExecutorCallbackCall,而ExecutorCallbackCall就是接口Call的实现类,那么,call.enqueue()时,将会执行ExecutorCallbackCall的enqueue方法,看下ExecutorCallbackCall的enqueue(final Callback<T> callback)源码:

      @Override
        public void enqueue(final Callback<T> callback) {
          Objects.requireNonNull(callback, "callback == null");
    
          delegate.enqueue(
              new Callback<T>() {
                @Override
                public void onResponse(Call<T> call, final Response<T> response) {
                  callbackExecutor.execute(
                      () -> {
                        if (delegate.isCanceled()) {
                          // Emulate OkHttp's behavior of throwing/delivering an IOException on
                          // cancellation.
                          callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
                        } else {
                          callback.onResponse(ExecutorCallbackCall.this, response);
                        }
                      });
                }
    
                @Override
                public void onFailure(Call<T> call, final Throwable t) {
                  callbackExecutor.execute(() -> callback.onFailure(ExecutorCallbackCall.this, t));
                }
              });
        }
    

    显然,线程就是通过callbackExecutor.execute()切换的,看下callbackExecutor怎么来的。
    通过代码追踪,发现,callbackExecutor来自Retrofit中的build(),而当我们创建Retrofit的时候,就调用了这个方法。

    三、Retrofit.build()

    public final class Retrofit {
        public Retrofit build() {
            //这里仅贴出获取callbackExecutor的代码
            ...
            Executor callbackExecutor = this.callbackExecutor;
            if (callbackExecutor == null) {
               callbackExecutor = platform.defaultCallbackExecutor();
            }
            ...
         }
    
        public static final class Builder {
             public Builder() {
                this(Platform.get());
             }
        }
    }
    class Platform {
      private static final Platform PLATFORM = findPlatform();
    
      static Platform get() {
        return PLATFORM;
      }
    
      private static Platform findPlatform() {
        return "Dalvik".equals(System.getProperty("java.vm.name"))
            ? new Android() //
            : new Platform(true);
      }
    
       static final class Android extends Platform {
           Android() {
             super(Build.VERSION.SDK_INT >= 24);
           }
    
          @Override
           public Executor defaultCallbackExecutor() {
              return new MainThreadExecutor();
           }
       }
    
      static final class MainThreadExecutor implements Executor {
          private final Handler handler = new Handler(Looper.getMainLooper());
    
          @Override
          public void execute(Runnable r) {
            handler.post(r);
          }
        }
    }
    
    

    platform是通过Platform.get()获取的,System.getProperty("java.vm.name")获取的是java VM的名称,显然,Android系统下将返回Android(),Android是Platform实现类,当调用latform.defaultCallbackExecutor()时,将返回一个MainThreadExecutor对象,而,当执行MainThreadExecutor.execute的时候,通过new Handler(Looper.getMainLooper())讲子线程切到了UI线程。

    四、如何让Retrofit请求结束后的回调中还在子线程

       val client = Retrofit.Builder().apply {
                    baseUrl("")
                    callbackExecutor(ThreadExecutor())
                    addConverterFactory(ScalarsConverterFactory.create())
                    client(OkHttpHolder.okHttpClient)
                }.build()
        class ThreadExecutor : Executor {
            override fun execute(r: Runnable) {
                r.run()
            }
        }
    

    给Retrofit重新创造一个Executor就行了。

    相关文章

      网友评论

          本文标题:Retrofit2线程切换

          本文链接:https://www.haomeiwen.com/subject/esvtmdtx.html