Android实战----Android Retrofit是怎么将回调函数放到UI线程(主线程)中的(源码分析)
Posted Herman-Hong
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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获取并运行在主线程中。
以上是关于Android实战----Android Retrofit是怎么将回调函数放到UI线程(主线程)中的(源码分析)的主要内容,如果未能解决你的问题,请参考以下文章