下面大家先看一段代码:
private void test(View view,final String from) {
view.post(new Runnable() {
@Override
public void run() {
Log.e("MainActivity", from+"--->View" + System.currentTimeMillis());
}
});
new Handler().post(new Runnable() {
@Override
public void run() {
Log.e("MainActivity", from + "--->Handler" + System.currentTimeMillis());
}
});
runOnUiThread(new Runnable() {
@Override
public void run() {
Log.e("MainActivity", from + "--->runOnUiThread" + System.currentTimeMillis());
}
});
}
06-21 14:41:19.255 7149-7149/com.duanchao.testapplication E/MainActivity: onResume--->runOnUiThread1466491279258
06-21 14:41:19.275 7149-7149/com.duanchao.testapplication E/MainActivity: onResume--->Handler1466491279277
06-21 14:41:19.335 7149-7149/com.duanchao.testapplication E/MainActivity: onResume--->View1466491279341
大家可以发现runOnUiThread时间明显比其他两个执行的早,而View.post()时间明显比其他两个执行的晚,大家可能会说程序执行是需要时间的,对,是这样的,但是需要这么长的时间吗?带着这个疑问咱们再看下一段日志:
06-21 15:10:51.185 28592-28592/com.duanchao.testapplication E/MainActivity: onCreate--->runOnUiThread1466493051194
06-21 15:10:51.195 28592-28592/com.duanchao.testapplication E/MainActivity: onResume--->runOnUiThread1466493051196
06-21 15:10:51.205 28592-28592/com.duanchao.testapplication E/MainActivity: onCreate--->Handler1466493051211
06-21 15:10:51.205 28592-28592/com.duanchao.testapplication E/MainActivity: onResume--->Handler1466493051212
06-21 15:10:51.255 28592-28592/com.duanchao.testapplication E/MainActivity: onCreate--->View1466493051264
06-21 15:10:51.255 28592-28592/com.duanchao.testapplication E/MainActivity: onResume--->View1466493051264
这段日志是在OnCreate和onResume里分别调用了test()方法,很明显OnCreate中的runOnUiThread、Handler().post(),view.post(),执行时间相隔还是很长,onResume也同样如此,但是runOnUiThread()在onResume和OnCreate两次调用的时间间隔很短,Handler().post(),view.post()也同样如此。那么问题就来了,这是为什么呢?其实大家都知道在Android中线程之间的交互的基础就是handler、looper、messageQueue,所以不论是runOnUiThread()还是view.post()最终还是使用了handler的基本原理。那么问题就又来了,既然原理相同调用时间也相同怎么在执行的时间上有这么大的差距呢?下面就给大家通过源码来分析一下这个问题。
下面咱们先从最简单的runOnUiThread()来看源码:
public final void runOnUiThread(Runnable action) {
if (Thread.currentThread() != mUiThread) {
mHandler.post(action);
} else {
action.run();
}
}
这是runOnUiThread()方法的源码,从源码可以看到,当一个Runnable进来时,判断当前线程是否是主线程,如果是主线程直接调用其run()方法了,不是主线程则调用handler的post()回到了handler。不管是onResume还是OnCreate里调用runOnUiThread()只要是主线程中调用,其Runnable的run()方法立刻就执行。(结论一)
下面咱们再看一下view.post()的源码:
public boolean post(Runnable action) {
final AttachInfo attachInfo = mAttachInfo;
if (attachInfo != null) {
return attachInfo.mHandler.post(action);
}
// Assume that post will succeed later
ViewRootImpl.getRunQueue().post(action);
return true;
}
它先判断了一个叫attachInfo是不是为null,如果不是null,调用了Handler的post()方法回到了handler,那么mAttachInfo是一个什么东东呢?下面我们再看一段代码:
/**
* Returns true if this view is currently attached to a window.
*/
public boolean isAttachedToWindow() {
return mAttachInfo != null;
}ViewRootImpl
如上mAttachInfo是用来判断是否attached到window的,这里留一个疑问即view什么时候attached到window上的呢?当为null的时候调用ViewRootImpl.getRunQueue().post(action),那么它的调用时机是什么呢?通过跟踪源码可以得到在ViewRootImpl的一系列方法中,比如draw(boolean)等。而ViewRootImpl.getRunQueue().post(action)的处理action是handler.postDelayed(handlerAction.action, handlerAction.delay)最后也回归到了handler。
下面再看一段日志:
06-21 18:28:54.055 25805-25805/com.duanchao.testapplication E/MainActivity: onCreate1466504934063
06-21 18:28:54.075 25805-25805/com.duanchao.testapplication E/MainActivity: onCreate--->runOnUiThread146650493407906-21 18:28:54.075 25805-25805/com.duanchao.testapplication E/MainActivity: onStart1466504934080
06-21 18:28:54.075 25805-25805/com.duanchao.testapplication E/MainActivity: onResume1466504934083
06-21 18:28:54.085 25805-25805/com.duanchao.testapplication E/MainActivity: onCreate--->Handler1466504934091
06-21 18:28:54.095 25805-25805/com.duanchao.testapplication E/TestView: onAttachedToWindow1466504934102
06-21 18:28:54.185 25805-25805/com.duanchao.testapplication E/MainActivity: onCreate--->View1466504934191
06-21 18:28:54.195 25805-25805/com.duanchao.testapplication E/TestView: onDraw1466504934204
抛开runOnUiThread不说因为上面已经说了该方法在主线程立刻会执行的,Handler().post()是在生命周期onResume之后执行的,而view.post()是在onAttachedWindow之后执行,也就是说ViewRootImpl.getRunQueue().post(action)是在onAttachedWindow之后执行的。由此我们得出一个结论,当程序启动一个activity时,OnCreate、onStart、onResume任务都添加到了主线程Looper的messageQueue中,在这个三个生命周期使用handler.post()都添加到messageQueue队列尾部,等待执行。而View.post(),最终也会添加到messageQueue队列中,等待onAttachedToWindow执行之后执行。(结论二)
下面我们再看一段日志:
06-21 18:42:09.985 17310-17310/com.duanchao.testapplication E/MainActivity: onClick--->runOnUiThread1466505729990
06-21 18:42:09.985 17310-17310/com.duanchao.testapplication E/MainActivity: onClick--->View1466505729990
06-21 18:42:09.985 17310-17310/com.duanchao.testapplication E/MainActivity: onClick--->Handler1466505729990
当在onResume之后点击某一button时打印的日志,由此看见当前面条件都满足时,在调用这三个post()方法时,都添加到messageQueue中,在每一个任务量小的时基本是同时执行的。那么我们就可以得出一个结论,在界面绘制成功以后再调用这三个方法时,当在子线程中调用时其效果是一样的,当在主线程中runOnUiThread是立刻执行该任务,而其他两个是加载到messageQueue队尾,当前面任务全部执行完毕再执行。(结论三)
下面我们再看一段终极日志来验证前面的结论:
06-21 18:54:19.975 7602-7602/com.duanchao.testapplication E/MainActivity: 前onClick--->runOnUiThread1466506459983
06-21 18:54:19.985 7602-7602/com.duanchao.testapplication E/MainActivity: 后onClick--->runOnUiThread1466506459993
06-21 18:54:19.985 7602-7602/com.duanchao.testapplication E/MainActivity: 前onClick--->View1466506459993
06-21 18:54:19.985 7602-7602/com.duanchao.testapplication E/MainActivity: 前onClick--->Handler1466506459993
06-21 18:54:19.985 7602-7602/com.duanchao.testapplication E/MainActivity: onPause1466506459994
06-21 18:54:19.995 7602-7602/com.duanchao.testapplication E/MainActivity: 后onClick--->View1466506460002
06-21 18:54:19.995 7602-7602/com.duanchao.testapplication E/MainActivity: 后onClick--->Handler1466506460002
06-21 18:54:20.005 7602-7602/com.duanchao.testapplication E/SecondActivity: onCreate1466506460007
06-21 18:54:20.005 7602-7602/com.duanchao.testapplication E/SecondActivity: onStart1466506460007
06-21 18:54:20.005 7602-7602/com.duanchao.testapplication E/SecondActivity: onResume1466506460009
06-21 18:54:20.385 7602-7602/com.duanchao.testapplication E/MainActivity: onStop1466506460391
06-21 18:57:09.725 7602-7602/com.duanchao.testapplication E/SecondActivity: onPause1466506629732
06-21 18:57:09.735 7602-7602/com.duanchao.testapplication E/MainActivity: onActivityResult1466506629742
06-21 18:57:09.735 7602-7602/com.duanchao.testapplication E/MainActivity: onActivityResult--->runOnUiThread1466506629742
06-21 18:57:09.735 7602-7602/com.duanchao.testapplication E/MainActivity: onStart1466506629742
06-21 18:57:09.735 7602-7602/com.duanchao.testapplication E/MainActivity: onResume1466506629743
06-21 18:57:09.755 7602-7602/com.duanchao.testapplication E/MainActivity: onActivityResult--->View1466506629757
06-21 18:57:09.755 7602-7602/com.duanchao.testapplication E/MainActivity: onActivityResult--->Handler1466506629757
06-21 18:57:10.095 7602-7602/com.duanchao.testapplication E/SecondActivity: onStop1466506630104
06-21 18:57:10.095 7602-7602/com.duanchao.testapplication E/SecondActivity: onDestroy1466506630104
onclick的代码如下:
view.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
test(view,"前onClick");
startActivityForResult(new Intent(MainActivity.this, SecondActivity.class), 100);
test(view,"后onClick");
}
});
验证结论一:所有的runOnUiThread都在其调用方法中执行的。
结论二:在onclick中第一次调用test()时,将handler和View.post()的任务加载到了messageQueue的队列中,调用startActivityForResult时将MainActivity的stop任务添加到了队列中,当第二次调用test()时,又将handler和View.post()的任务加载到了messageQueue的队列中,然后启动secondActivity时,OnCreate、onStart、onResume都添加队列中。如上log可以验证改结论正确。
结论三:当Activity绘制成功以后,不论是在哪里执行handler().post()和view.post()是没有区别的。以上log验证正确。