【Android实战】----Android Retrofit是怎么将回调函数放到UI线程(主线程)中的(源码分析)

一、简介

集成过Retrofit的猿们都知道,callback是运行在主线程中的,不用再通过异步机制处理。那么是怎么实现的呢,下面从源码角度进行分析,其中涉及到Android异步机制(Handler、Message、Looper、MessageQueue),猿们自行脑补。


二、Retrofit的创建

下面从Retrofit的创建开始,其中的秘密也在其中

Retrofit mRetrofit = new Retrofit.Builder()
                .baseUrl(UrlConfig.ROOT_URL)
                .client(genericClient())
                .addConverterFactory(GsonConverterFactory.create())
                .build();

.Builder()

public Builder() {
      this(Platform.get());
    }

private static final Platform PLATFORM = findPlatform();

  static Platform get() {
    return PLATFORM;
  }

private static Platform findPlatform() {
    try {
      Class.forName("android.os.Build");
      if (Build.VERSION.SDK_INT != 0) {
        return new Android();
      }
    } catch (ClassNotFoundException ignored) {
    }
    try {
      Class.forName("java.util.Optional");
      return new Java8();
    } catch (ClassNotFoundException ignored) {
    }
    try {
      Class.forName("org.robovm.apple.foundation.NSObject");
      return new IOS();
    } catch (ClassNotFoundException ignored) {
    }
    return new Platform();
  }

static class Android extends Platform {
    @Override public Executor defaultCallbackExecutor() {
      return new MainThreadExecutor();
    }

    @Override CallAdapter.Factory defaultCallAdapterFactory(Executor callbackExecutor) {
      return new ExecutorCallAdapterFactory(callbackExecutor);
    }

    static class MainThreadExecutor implements Executor {
      private final Handler handler = new Handler(Looper.getMainLooper());

      @Override public void execute(Runnable r) {
        handler.post(r);
      }
    }
  }

从上到下依次执行,最终到Android中,秘密就在defaultCallbackExecutor()中,从MainThreadExecutor命名就可以看出其作用,下面代码更是进行了验证

private final Handler handler = new Handler(Looper.getMainLooper());


不是别的就是基于主线程中的Looper创建了Handler,那么利用本Handler post进的Runnable就执行在主线程(不懂的猿们可自行脑补)中了。

题外话:还有更常见的一种是异步消息处理,在主线程中采用下列方式创建Handler

private final Handler handler = new Handler()

那么其中的Looper也是主线程中的Looper,Looper是从线程本地变量中获取的。

/**
     * Return the Looper object associated with the current thread.  Returns
     * null if the calling thread is not associated with a Looper.
     */
    public static @Nullable Looper myLooper() {
        return sThreadLocal.get();
    }

这种使用默认new Handler()构造的只能在主线程中创建,使用new Handler(Looper.getMainLooper())创建跟在哪儿创建无关,Looper都是主线程中的Looper

/**
     * Returns the application's main looper, which lives in the main thread of the application.
     */
    public static Looper getMainLooper() {
        synchronized (Looper.class) {
            return sMainLooper;
        }
    }

sMainLooper是应用的主线程looper,是由Android系统为应用创建的,不需要自己创建。

/**
     * Initialize the current thread as a looper, marking it as an
     * application's main looper. The main looper for your application
     * is created by the Android environment, so you should never need
     * to call this function yourself.  See also: {@link #prepare()}
     */
    public static void prepareMainLooper() {
        prepare(false);
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            sMainLooper = myLooper();
        }
    }


言归正传,看Retrofit的build

/**
     * Create the {@link Retrofit} instance using the configured values.
     * <p>
     * Note: If neither {@link #client} nor {@link #callFactory} is called a default {@link
     * OkHttpClient} will be created and used.
     */
    public Retrofit build() {
      if (baseUrl == null) {
        throw new IllegalStateException("Base URL required.");
      }

      okhttp3.Call.Factory callFactory = this.callFactory;
      if (callFactory == null) {
        callFactory = new OkHttpClient();
      }

      Executor callbackExecutor = this.callbackExecutor;
      if (callbackExecutor == null) {
        callbackExecutor = platform.defaultCallbackExecutor();
      }

      // Make a defensive copy of the adapters and add the default Call adapter.
      List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
      adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));

      // Make a defensive copy of the converters.
      List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);

      return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
          callbackExecutor, validateEagerly);
    }
其中callbackExecutor,就是上面创建的MainThreadExecutor,这里要记住,后面callback调用的时候要用

三、callBack的回调

先看使用

/**
     * 将call加入队列并实现回调
     *
     * @param context          应用上下文
     * @param call             调入的call
     * @param retrofitCallBack 回调
     * @param method           调用方法标志,回调用
     * @param <T>              泛型参数
     */
    public static <T> void addToEnqueue(final Context context, Call<T> call,
                                        final RetrofitCallBack retrofitCallBack, final int method) {
        call.enqueue(new Callback<T>() {
            @Override
            public void onResponse(Call<T> call, Response<T> response) {
                LogUtil.d("retrofit back code ====" + response.code());
                if (null != response.body()) {
                    if (response.code() == 200) {
                        LogUtil.d("retrofit back body ====" + new Gson().toJson(response.body()));
                        retrofitCallBack.onResponse(response, method);
                    } else {
                        LogUtil.d("toEnqueue, onResponse Fail:" + response.code());
                        ToastUtil.makeShortText(context, "网络连接错误" + response.code());
                        retrofitCallBack.onFailure(response, method);
                    }
                } else {
                    LogUtil.d("toEnqueue, onResponse Fail m:" + response.message());
                    ToastUtil.makeShortText(context, "网络连接错误" + response.message());
                    retrofitCallBack.onFailure(response, method);
                }
            }

            @Override
            public void onFailure(Call<T> call, Throwable t) {
                LogUtil.d("toEnqueue, onResponse Fail unKnown:" + t.getMessage());
                t.printStackTrace();
                ToastUtil.makeShortText(context, "网络连接错误" + t.getMessage());
                retrofitCallBack.onFailure(null, method);
            }
        });
    }

将callback加入到call的enqueue中,看下enqueue中都做了什么

@Override public void enqueue(final Callback<T> callback) {
      if (callback == null) throw new NullPointerException("callback == null");

      delegate.enqueue(new Callback<T>() {
        @Override public void onResponse(Call<T> call, final Response<T> response) {
          callbackExecutor.execute(new Runnable() {
            @Override public void run() {
              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(new Runnable() {
            @Override public void run() {
              callback.onFailure(ExecutorCallbackCall.this, t);
            }
          });
        }
      });
    }


其他不管,那么callback的方法就是在callbackExecutor被调用的,而这里的callbackExecutor就是MainThreadExecutor,因此这里的callback方法就运行在主线程中了。


总结:在这方面Retrofit对okhttp的封装,就好比Volley(最新的)对HttpUrlConnection的封装一样,都是采用这种方式将回调方法运行在主线程中的,其中都用到了Android最基本的异步机制(Handler、Looper、Message、MessageQueue)。通过基于主线程中的Looper创建Handler,从而实现通过此Handler post的消息能够被主线程中的Looper获取并运行在主线程中。



发布了168 篇原创文章 · 获赞 205 · 访问量 82万+

猜你喜欢

转载自blog.csdn.net/honghailiang888/article/details/54341486