- runOnUIThread(Runable run)和Handler有何关系其原理又是什么?
- handler.post(Runable run) 回调方法是运行在那个线程?
- 在UI Thread 创建Handler时,没有手动去调用 Looper.preper()、Looper.loop()方法为何没有抛出异常?
- Looper 在UI Thread中轮询消息时,为何没有造成阻塞?
- Toast为何在子线程调用会抛出异常?
上述问题都是和Handler机制相关的,在实际开发中有遇到过吗?有深入了解过吗?没有关系,在这里我们再慢慢探讨。还对Handler流程不熟悉的可以在这里找到答案 Handler原理剖析
runOnUIThread的工作原理
该方法是Activity的公共方法,下面是该方法的注释:
在UI线程中运行执行的action(手动指定的回调函数),如果当前线程是UI线程,回调函数马上执行,如果当前线程不是UI线程,那回调函数被加入到UI线程的事件队列
从上面的注释可以看出,该方法分为两种逻辑执行:1、直接运行在UI Thread;2、将该事件加入到UI Thread的消息队列;
第一种还好理解,那第二种的消息队列和我们一直讲的Handler有何关系呢,要理清这些关系,从源码开始:
//源码
public final void runOnUiThread(Runnable action) {
if (Thread.currentThread() != mUiThread) {
//如果当前线程是UI线程,这将action加入到消息队列
mHandler.post(action);
} else {
//直接调用run
action.run();
}
}
//Activity的UI Thread中直接使用
runOnUiThread(new Runnable() {
@Override public void run() {
// TODO: 你的代码
}
});
该方法源码还是挺简洁的,先来action.run()直接调用的逻辑,结合源码和在Activity的UI Thread中直接使用的代码来看,action.run()是直接运行在UI Thread的,没有任何异步操作,比较好理解,所有如果是在activity中直接调用的runOnUiThread,没有开线程的情况下,最好不要在run方法体中做耗时操作,不然会造成UI Thread 的阻塞,接下来mHandler.post(action);才是我们要说的重点在实际代码中我们如果按如下方法调用,会执行mHandler.post(action);:
new Thread() {
@Override public void run() {
runOnUiThread(new Runnable() {
@Override public void run() {
// TODO: 你的代码
}
});
}
}.start();
进入mHandler.post(action)的源码:
public final boolean post(Runnable r)
{
return sendMessageDelayed(getPostMessage(r), 0);
}
这样的代码和Handler发送消息一样的流程了,还不知道的请看Handler原理剖析,
其实理解整个逻辑,关键是理解getPostMessage(r):
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}
m.callback = r; 这行代码就是将我们传入的Runable对象赋值给message的callback成员变量,因为mHandler.post 实在主线程中执行,所以loop()会运行在主线成中所以消息会在主线程中接收处理。我们通过源码来验证一下我们的逻辑是否正确,现在进入到Handler的消息分发方法中去:
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
msg.callback != null 这段代码肯定成立,因为上文中的getPostMessage方法中已经将我们传入的callback对象赋值给msg.callback,所以会直接执行到 handleCallback(msg); 那么我们再来看handleCallback(msg):
private static void handleCallback(Message message) {
message.callback.run();
}
没错,只有一行代码,message.callback.run(); 这行代码是在UI线程中执行的,那为什么呢?你怎么看出来的呢?好吧,我们要知其然也要知其所以然,那么我们再详细解释一下吧。上文的mHandler是Activity的成员变量,并且是在主线程中进行初始化,所以Looper.preper()、Looper.loop()等方法,就会在主线程中调用,还记得loop()做了那些事吗?不记得的请看 Handler原理剖析,loop()轮询messageQueue中的消息,如果没有消息就退出轮询,如果有,就执行message.target.dispatchMessage进行消息分发,源码就不贴出来了,所以message.target.dispatchMessage就是在主线程中调用,由此推出上文的 message.callback.run();也会在主线程中执行,所以 runOnUiThread的run回调方法也就是在子线程中执行。对没,错,这就是一个Handler子线程发消息,主线程接收消息的一种封装而已。
handler.post(Runable run) 回调方法是运行在那个线程
其实这个问题已经在第一个问题中得到了解决,我们这里简单分析一下就行;
new Handler().post(new Runnable() {
@Override public void run() {
// TODO: you code
}
});
我们在开发中时常写出这样的代码,而且还在run()中处理一些耗时任务,对,没错,你加班改的bug就是我写的。
在主线程中创建Handler对象同时将Runable加入到主线程的消息队列,所以run()会在主线程中调用,和第一个问题相类似的流程不在赘述。
在UI Thread 创建Handler时,没有手动去调用 Looper.preper()、Looper.loop()方法为何没有抛出异常?
要回答这样的一系列问题,需要了解到Android程序的入口,那么Android程序真正的入口是在哪里呢?想想java程序的入口是某个类的main(),而Android程序的main函数实在类ActivityThread中,所以Android程序的入口就是ActivityThread的main(),这个我们直接抛出结论,至于其过程和原理这里不会探讨。ActivityThread的源码大概有5000多行,我们并不是要全部看完,只需要找到我们需要的代码就行了。
public static void main(String[] args) {
....
//创建Looper对象,其实和preper()实现类似,只是该方法通常用于ActivityThread中
Looper.prepareMainLooper();
//创建ActivityThread对象
ActivityThread thread = new ActivityThread();
//建立Binder通道 (创建新线程)
thread.attach(false);
//消息循环运行
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
根据ActivityThread的源码可以看出,在应用程序启动的时候在ActivityThread的main方法中手动调用了Looper.preper()、Looper.loop();
Looper 在UI Thread中轮询消息时,为何没有造成阻塞?
其实这个问题设计到的东西还是挺多的,需要明白Handler原理、Process/Thread、Android Binder IPC、Linux pipe/epoll机制、Activity的启动及其生命周期等等一大堆东西,当然这里我们就不会去深入了。
要了解这个问题,首先从ActivityThread的handlerMessage方法开始:
public void handleMessage(Message msg) {
if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
switch (msg.what) {
case LAUNCH_ACTIVITY: {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
final ActivityClientRecord r = (ActivityClientRecord) msg.obj;
r.packageInfo = getPackageInfoNoCheck(
r.activityInfo.applicationInfo, r.compatInfo);
handleLaunchActivity(r, null);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
} break;
case RELAUNCH_ACTIVITY: {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityRestart");
ActivityClientRecord r = (ActivityClientRecord)msg.obj;
handleRelaunchActivity(r);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
} break;
case PAUSE_ACTIVITY:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityPause");
handlePauseActivity((IBinder)msg.obj, false, (msg.arg1&1) != 0, msg.arg2,
(msg.arg1&2) != 0);
maybeSnapshot();
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
case PAUSE_ACTIVITY_FINISHING:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityPause");
handlePauseActivity((IBinder)msg.obj, true, (msg.arg1&1) != 0, msg.arg2,
(msg.arg1&1) != 0);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
case STOP_ACTIVITY_SHOW:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStop");
handleStopActivity((IBinder)msg.obj, true, msg.arg2);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
case STOP_ACTIVITY_HIDE:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStop");
handleStopActivity((IBinder)msg.obj, false, msg.arg2);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
case SHOW_WINDOW:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityShowWindow");
handleWindowVisibility((IBinder)msg.obj, true);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
case HIDE_WINDOW:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityHideWindow");
handleWindowVisibility((IBinder)msg.obj, false);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
case RESUME_ACTIVITY:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityResume");
handleResumeActivity((IBinder) msg.obj, true, msg.arg1 != 0, true);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
case SEND_RESULT:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityDeliverResult");
handleSendResult((ResultData)msg.obj);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
case DESTROY_ACTIVITY:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityDestroy");
handleDestroyActivity((IBinder)msg.obj, msg.arg1 != 0,
msg.arg2, false);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
case BIND_APPLICATION:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "bindApplication");
AppBindData data = (AppBindData)msg.obj;
handleBindApplication(data);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
case EXIT_APPLICATION:
if (mInitialApplication != null) {
mInitialApplication.onTerminate();
}
Looper.myLooper().quit();
break;
case NEW_INTENT:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityNewIntent");
handleNewIntent((NewIntentData)msg.obj);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
case RECEIVER:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "broadcastReceiveComp");
handleReceiver((ReceiverData)msg.obj);
maybeSnapshot();
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
case CREATE_SERVICE:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceCreate");
handleCreateService((CreateServiceData)msg.obj);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
case BIND_SERVICE:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceBind");
handleBindService((BindServiceData)msg.obj);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
case UNBIND_SERVICE:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceUnbind");
handleUnbindService((BindServiceData)msg.obj);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
case SERVICE_ARGS:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceStart");
handleServiceArgs((ServiceArgsData)msg.obj);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
case STOP_SERVICE:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceStop");
handleStopService((IBinder)msg.obj);
maybeSnapshot();
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
case CONFIGURATION_CHANGED:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "configChanged");
mCurDefaultDisplayDpi = ((Configuration)msg.obj).densityDpi;
handleConfigurationChanged((Configuration)msg.obj, null);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
case CLEAN_UP_CONTEXT:
ContextCleanupInfo cci = (ContextCleanupInfo)msg.obj;
cci.context.performFinalCleanup(cci.who, cci.what);
break;
case GC_WHEN_IDLE:
scheduleGcIdler();
break;
case DUMP_SERVICE:
handleDumpService((DumpComponentInfo)msg.obj);
break;
case LOW_MEMORY:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "lowMemory");
handleLowMemory();
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
case ACTIVITY_CONFIGURATION_CHANGED:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityConfigChanged");
handleActivityConfigurationChanged((IBinder)msg.obj);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
case PROFILER_CONTROL:
handleProfilerControl(msg.arg1 != 0, (ProfilerInfo)msg.obj, msg.arg2);
break;
case CREATE_BACKUP_AGENT:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "backupCreateAgent");
handleCreateBackupAgent((CreateBackupAgentData)msg.obj);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
case DESTROY_BACKUP_AGENT:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "backupDestroyAgent");
handleDestroyBackupAgent((CreateBackupAgentData)msg.obj);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
case SUICIDE:
Process.killProcess(Process.myPid());
break;
case REMOVE_PROVIDER:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "providerRemove");
completeRemoveProvider((ProviderRefCount)msg.obj);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
case ENABLE_JIT:
ensureJitEnabled();
break;
case DISPATCH_PACKAGE_BROADCAST:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "broadcastPackage");
handleDispatchPackageBroadcast(msg.arg1, (String[])msg.obj);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
case SCHEDULE_CRASH:
throw new RemoteServiceException((String)msg.obj);
case DUMP_HEAP:
handleDumpHeap(msg.arg1 != 0, (DumpHeapData)msg.obj);
break;
case DUMP_ACTIVITY:
handleDumpActivity((DumpComponentInfo)msg.obj);
break;
case DUMP_PROVIDER:
handleDumpProvider((DumpComponentInfo)msg.obj);
break;
case SLEEPING:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "sleeping");
handleSleeping((IBinder)msg.obj, msg.arg1 != 0);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
case SET_CORE_SETTINGS:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "setCoreSettings");
handleSetCoreSettings((Bundle) msg.obj);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
case UPDATE_PACKAGE_COMPATIBILITY_INFO:
handleUpdatePackageCompatibilityInfo((UpdateCompatibilityData)msg.obj);
break;
case TRIM_MEMORY:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "trimMemory");
handleTrimMemory(msg.arg1);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
case UNSTABLE_PROVIDER_DIED:
handleUnstableProviderDied((IBinder)msg.obj, false);
break;
case REQUEST_ASSIST_CONTEXT_EXTRAS:
handleRequestAssistContextExtras((RequestAssistContextExtras)msg.obj);
break;
case TRANSLUCENT_CONVERSION_COMPLETE:
handleTranslucentConversionComplete((IBinder)msg.obj, msg.arg1 == 1);
break;
case INSTALL_PROVIDER:
handleInstallProvider((ProviderInfo) msg.obj);
break;
case ON_NEW_ACTIVITY_OPTIONS:
Pair<IBinder, ActivityOptions> pair = (Pair<IBinder, ActivityOptions>) msg.obj;
onNewActivityOptions(pair.first, pair.second);
break;
case CANCEL_VISIBLE_BEHIND:
handleCancelVisibleBehind((IBinder) msg.obj);
break;
case BACKGROUND_VISIBLE_BEHIND_CHANGED:
handleOnBackgroundVisibleBehindChanged((IBinder) msg.obj, msg.arg1 > 0);
break;
case ENTER_ANIMATION_COMPLETE:
handleEnterAnimationComplete((IBinder) msg.obj);
break;
}
if (DEBUG_MESSAGES) Slog.v(TAG, "<<< done: " + codeToString(msg.what));
}
ActivityThread的内部类H继承于Handler,通过handler消息机制,简单说Handler机制用于同一个进程的线程间通信。Activity的生命周期都是依靠主线程的Looper.loop,当收到不同Message时则采用相应措施:在H.handleMessage(msg)方法中,根据接收到不同的msg,执行相应的生命周期。比如收到msg=H.LAUNCH_ACTIVITY,则调用ActivityThread.handleLaunchActivity()方法,最终会通过反射机制,创建Activity实例,然后再执行Activity.onCreate()等方法; 再比如收到msg=H.PAUSE_ACTIVITY,则调用ActivityThread.handlePauseActivity()方法,最终会执行Activity.onPause()等方法,主线程的消息又是哪来的呢?当然是App进程中的其他线程通过Handler发送给主线程,epoll(请百度)当没有消息的时候会执行epoll.wait,等待句柄写的时候再唤醒,这个时候其实是阻塞的。所有的ui操作都通过handler来发消息操作。比如屏幕刷新16ms一个消息,各种点击事件,Activity的生命周期函数执行消息,所以就会有句柄写操作,唤醒上文的wait操作,因此不会被造成主线程的阻塞。看到这是不是内心在哦,原来如此!
Toast为何在子线程调用会抛出异常?
从Toast的源码中可以看出,其内部也有Handler发送消息的流程,这样一来这个问题就解决了,其根本原因还是要归类于Handler的原理,所以本文中的问题都是围绕Handler来进行。只要把Handler搞明白,则万变不离其宗;本文的主要目的也是通过这些问题来加深对Handler的理解