【Android实战】----Android Retrofit是怎么将回调函数放到UI线程(主线程)中的(源码分析)
2017-01-11 11:27
363 查看
一、简介
集成过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()
从上到下依次执行,最终到Android中,秘密就在defaultCallbackExecutor()中,从MainThreadExecutor命名就可以看出其作用,下面代码更是进行了验证
不是别的就是基于主线程中的Looper创建了Handler,那么利用本Handler post进的Runnable就执行在主线程(不懂的猿们可自行脑补)中了。
题外话:还有更常见的一种是异步消息处理,在主线程中采用下列方式创建Handler
那么其中的Looper也是主线程中的Looper,Looper是从线程本地变量中获取的。
这种使用默认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系统为应用创建的,不需要自己创建。
言归正传,看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的回调
先看使用
将callback加入到call的enqueue中,看下enqueue中都做了什么
其他不管,那么callback的方法就是在callbackExecutor被调用的,而这里的callbackExecutor就是MainThreadExecutor,因此这里的callback方法就运行在主线程中了。
总结:在这方面Retrofit对okhttp的封装,就好比Volley(最新的)对HttpUrlConnection的封装一样,都是采用这种方式将回调方法运行在主线程中的,其中都用到了Android最基本的异步机制(Handler、Looper、Message、MessageQueue)。通过基于主线程中的Looper创建Handler,从而实现通过此Handler post的消息能够被主线程中的Looper获取并运行在主线程中。
集成过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获取并运行在主线程中。
相关文章推荐
- 【Android实战】----从Retrofit源码分析到Java网络编程以及HTTP权威指南想到的
- [Android] Retrofit 源码分析之 Retrofit 对象
- Android:这是一份全面 &amp; 详细的Retrofit 2.0 源码分析指南
- [Android] Retrofit 源码分析之 ServiceMethod 对象
- Android:这是一份全面 &amp; 详细的Retrofit 2.0 源码分析指南
- Android:这是一份全面 &amp; 详细的Retrofit 2.0 源码分析指南
- android开源库—retrofit(附实战源码)
- Android:这是一份全面 &amp; 详细的Retrofit 2.0 源码分析指南
- android的技术分解以及Retrofit源码分析以及MVP框架封装使用
- 深入Android Handler源码,分析主线程、子线程通讯原理
- Android实战——AndFix的使用与源码分析
- Android:这是一份全面 &amp; 详细的Retrofit 2.0 源码分析指南
- 简略分析Android的Retrofit应用开发框架源码
- Android中的retrofit源码分析
- Android:这是一份全面 &amp; 详细的Retrofit 2.0 源码分析指南
- Android源码分析实战之JNI so库加载System.loadLibrary流程分析
- android Retrofit简单使用及源码分析
- React Native Android入门实战及深入源码分析系列(2)——React Native源码编译
- 【Android7.1.2源码解析系列】实战分析init.rc文件