Handler
一些面试问题:
- 1.一个线程有几个Handler?
- 2.一个线程有几个looper,如何保证的?
- 3.Handler内存泄漏原因?为什么其他的内部类没有说过这个问题?
- 4.为何主线程可以new Handler?如果想要在子线程中new handler要做什么准备
- 5.子线程中维护的Looper,消息队列无消息的时候处理方案是什么?有什么用?
- 6.既然可以存在多个Handler往MessageQueue中添加数据(发消息时各个Handler可能处于不同线程),那它内部是如何保证线程安全的?
- 7.我们使用Message时应该如何创建它?
- 8.Looper死循环为什么不会导致应用卡死?
首先了解Handle是用于线程间通讯的,是整个App中的通信框架。
最常用的sendMessage的流程
handle.sendMessage() ->messageQueue.enqueueMessage
looper.loop()->messageQueue.next()->handler.dispatchMessage()->handle.handleMessage()
其中会涉及到类包括MessageQueue和Looper。
1.Android启动主线程中的Handler
Handle发送消息到MessageQueue中,然后Looper进行一个死循环来从MessageQueue中取消息,特别是我们在子线程中使用Handle时,我们要自己去启动Looper,不然Handle根本不起作用。但是在Android的主线程中我们并没有手动去启动looper,那么它是怎么来的?
来看一下Android程序的主入口,ActivityThread.main()->
public static void main(String[] args) {
//省略部分代码
//这里启动了Looper
Looper.prepareMainLooper();
// Find the value for {@link #PROC_START_SEQ_IDENT} if provided on the command line.
// It will be in the format "seq=114"
long startSeq = 0;
if (args != null) {
for (int i = args.length - 1; i >= 0; --i) {
if (args[i] != null && args[i].startsWith(PROC_START_SEQ_IDENT)) {
startSeq = Long.parseLong(
args[i].substring(PROC_START_SEQ_IDENT.length()));
}
}
}
ActivityThread thread = new ActivityThread();
thread.attach(false, startSeq);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
// End of event ActivityThreadMain.
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
//Looper中是一个轮询操作
Looper.loop();
//执行到这里说明主线程中的Looper意外退出了,那么程序也就挂掉了
throw new RuntimeException("Main thread loop unexpectedly exited");
}
Looper中相关的方法分析:
/**
构建主线程的Looper和MessageQueue
*/
@Deprecated
public static void prepareMainLooper() {
//这里就是构建了一个不允许退出的Looper并放到了sThreadLocal(ThreadLocal)中
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
//主线程的Looper
sMainLooper = myLooper();
}
}
/**
quitAllowed是否允许退出
*/
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}
/**
looper的轮询操作
*/
public static void loop() {
//获取当前线程的Looper
final Looper me = myLooper();
//如果为空的话,说明Looper还没有创建
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
if (me.mInLoop) {
Slog.w(TAG, "Loop again would have the queued messages be executed"
+ " before this one completed.");
}
me.mInLoop = true;
// 确保该线程的身份是本地进程的身份,并跟踪该身份令牌实际上是什么。
Binder.clearCallingIdentity();
final long ident = Binder.clearCallingIdentity();
// 允许使用系统道具覆盖阈值。例如adb shell 'setprop log.looper.1000.main.slow 1 && 停止 && 开始'
final int thresholdOverride =
SystemProperties.getInt("log.looper."
+ Process.myUid() + "."
+ Thread.currentThread().getName()
+ ".slow", 0);
me.mSlowDeliveryDetected = false;
for (;;) {
//在当前Looper的MessageQueue中取Message
if (!loopOnce(me, ident, thresholdOverride)) {
return;
}
}
}
2.主线程的Handler都处理了什么?
public void handleMessage(Message msg) {
if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
switch (msg.what) {
//这个应该是初始化应用信息的,handleBindApplication中有设置应用的TargetVersion,时间格式(12或者24)等
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;
//处理应用退出,可以看到主线程的Looper调用了quit停止了
case EXIT_APPLICATION:
if (mInitialApplication != null) {
mInitialApplication.onTerminate();
}
Looper.myLooper().quit();
break;
//这里应该是处理广播接受
case RECEIVER:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "broadcastReceiveComp");
handleReceiver((ReceiverData)msg.obj);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
//创建服务
case CREATE_SERVICE:
if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
("serviceCreate: " + String.valueOf(msg.obj)));
}
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);
schedulePurgeIdler();
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
//应该是启动服务
case SERVICE_ARGS:
if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
("serviceStart: " + String.valueOf(msg.obj)));
}
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);
schedulePurgeIdler();
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
//配置信息发生变化(主题等)
case CONFIGURATION_CHANGED:
mConfigurationController.handleConfigurationChanged((Configuration) msg.obj);
break;
//移除上下文,看内部代码实现应该是注销广播的接受者和服务的Connection
case CLEAN_UP_CONTEXT:
ContextCleanupInfo cci = (ContextCleanupInfo)msg.obj;
cci.context.performFinalCleanup(cci.who, cci.what);
break;
//空闲时调用GC
case GC_WHEN_IDLE:
scheduleGcIdler();
break;
//转储服务 -不清楚做什么
case DUMP_SERVICE:
handleDumpService((DumpComponentInfo)msg.obj);
break;
//转储 GFXINFO -不清楚做什么
case DUMP_GFXINFO:
handleDumpGfxInfo((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 PROFILER_CONTROL:
handleProfilerControl(msg.arg1 != 0, (ProfilerInfo)msg.obj, msg.arg2);
break;
//创建备份--应该就是activity中创建备份的地方
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 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:
throwRemoteServiceException((String) msg.obj, msg.arg1);
break;
//处理转储堆
case DUMP_HEAP:
handleDumpHeap((DumpHeapData) msg.obj);
break;
//将 Activity 的状态打印到给定的流中。 如果您运行“adb shell dumpsys activity <activity_component_name>”,则会调用它。
case DUMP_ACTIVITY:
handleDumpActivity((DumpComponentInfo)msg.obj);
break;
//将提供者的状态打印到给定的流中。 如果您运行“adb shell dumpsys activity provider <provider_component_name>”,则会调用此方法。
case DUMP_PROVIDER:
handleDumpProvider((DumpComponentInfo)msg.obj);
break;
//核心设置(?)更改后,重启所有的Activity
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 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;
//一个新的Activity选项?
case ON_NEW_ACTIVITY_OPTIONS:
Pair<IBinder, ActivityOptions> pair = (Pair<IBinder, ActivityOptions>) msg.obj;
onNewActivityOptions(pair.first, pair.second);
break;
//进入动画完成
case ENTER_ANIMATION_COMPLETE:
handleEnterAnimationComplete((IBinder) msg.obj);
break;
//启用 Binder IPC 跟踪。
case START_BINDER_TRACKING:
handleStartBinderTracking();
break;
//应该就是停止Binder并销毁
case STOP_BINDER_TRACKING_AND_DUMP:
handleStopBinderTrackingAndDump((ParcelFileDescriptor) msg.obj);
break;
//本地语音交互开始
case LOCAL_VOICE_INTERACTION_STARTED:
handleLocalVoiceInteractionStarted((IBinder) ((SomeArgs) msg.obj).arg1,
(IVoiceInteractor) ((SomeArgs) msg.obj).arg2);
break;
//附加代理
case ATTACH_AGENT: {
Application app = getApplication();
handleAttachAgent((String) msg.obj, app != null ? app.mLoadedApk : null);
break;
}
/**
包安装触发的更新通过包更新接收器。在这里,我们尝试捕获由其他来源(例如覆盖)引起的 ApplicationInfo 更改。这意味着我们希望对代码更改尽可能保守。获取旧 ApplicationInfo 和新 ApplicationInfo 的差异,看看是否需要更改任何内容。
*/
case APPLICATION_INFO_CHANGED:
handleApplicationInfoChanged((ApplicationInfo) msg.obj);
break;
//运行隔离入口点
case RUN_ISOLATED_ENTRY_POINT:
handleRunIsolatedEntryPoint((String) ((SomeArgs) msg.obj).arg1,
(String[]) ((SomeArgs) msg.obj).arg2);
break;
//这里是12中对之前生命周期的一个统一入口,改为状态模式
case EXECUTE_TRANSACTION:
final ClientTransaction transaction = (ClientTransaction) msg.obj;
mTransactionExecutor.execute(transaction);
if (isSystem()) {
// Client transactions inside system process are recycled on the client side
// instead of ClientLifecycleManager to avoid being cleared before this
// message is handled.
transaction.recycle();
}
// TODO(lifecycler): Recycle locally scheduled transactions.
break;
//重新启动Activity,活动状态必须在 [ON_START..ON_STOP] 才能重新启动
case RELAUNCH_ACTIVITY:
handleRelaunchActivityLocally((IBinder) msg.obj);
break;
//清除资源
case PURGE_RESOURCES:
schedulePurgeIdler();
break;
//附加启动参数
case ATTACH_STARTUP_AGENTS:
handleAttachStartupAgents((String) msg.obj);
break;
//更新UI状态
case UPDATE_UI_TRANSLATION_STATE:
final SomeArgs args = (SomeArgs) msg.obj;
updateUiTranslationState((IBinder) args.arg1, (int) args.arg2,
(TranslationSpec) args.arg3, (TranslationSpec) args.arg4,
(List<AutofillId>) args.arg5, (UiTranslationSpec) args.arg6);
break;
//这里应该是对应内容提供者的,内容收集者
case SET_CONTENT_CAPTURE_OPTIONS_CALLBACK:
handleSetContentCaptureOptionsCallback((String) msg.obj);
break;
/**
在检测启动时调用,在加载任何应用程序代码之前。 通常这将被实现为简单地调用start来start检测线程,然后在onStart继续执行。
如果您不需要自己的线程——也就是说,您正在编写完全异步的检测(返回到事件循环以便应用程序可以运行),您可以简单地在此处开始检测,例如调用Context.startActivity开始适当的应用程序的第一个活动。
*/
case INSTRUMENT_WITHOUT_RESTART:
handleInstrumentWithoutRestart((AppBindData) msg.obj);
break;
//销毁上面的检测对象
case FINISH_INSTRUMENTATION_WITHOUT_RESTART:
handleFinishInstrumentationWithoutRestart();
break;
}
Object obj = msg.obj;
if (obj instanceof SomeArgs) {
((SomeArgs) obj).recycle();
}
if (DEBUG_MESSAGES) Slog.v(TAG, "<<< done: " + codeToString(msg.what));
}
可以看到和四大组件(Activity,Service,Broadcast,ContentProvider)相关的都有,还有应用信息的设置,启动和关闭应用,UI的更新
3.Handler的消息发送
最常使用的sendMessage:
public final boolean sendMessage(@NonNull Message msg) {
return sendMessageDelayed(msg, 0);
}
public final boolean sendMessageDelayed(@NonNull Message msg, long delayMillis) {
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
public boolean sendMessageAtTime(@NonNull Message msg, long uptimeMillis) {
//消息队列
MessageQueue queue = mQueue;
if (queue == null) {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
return false;
}
return enqueueMessage(queue, msg, uptimeMillis);
}
private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,
long uptimeMillis) {
//消息这里也就和Handler进行的绑定,所以这里也就是为什么Handler会有内存溢出的问题
//handler的处理一般都是作为内部类去使用,但是当handler持有外部类的引用时,而消息需要等待的时间比较长,
//例如20分钟,但是当前的Activity已经退出要销毁,根据GC的可达性分析,Message持有Handler,
//Handler又持有Activity的引用,所以这里GC就无法进行回收,从而发生异常。内存溢出很大的可能
//都是因为生命周期不一致引起的。
msg.target = this;
msg.workSourceUid = ThreadLocalWorkSource.getUid();
if (mAsynchronous) {
msg.setAsynchronous(true);
}
//见MessageQueue的方法分析
return queue.enqueueMessage(msg, uptimeMillis);
}
MessageQueue相关方法分析:
boolean enqueueMessage(Message msg, long when) {
//msg的target就是handler,如果没有那么这就没有消费者了
if (msg.target == null) {
throw new IllegalArgumentException("Message must have a target.");
}
//加锁保证在同一时刻只有一个插入消息队列的操作,并且没有其他的操作(取消息和消息退出)
synchronized (this) {
if (msg.isInUse()) {
throw new IllegalStateException(msg + " This message is already in use.");
}
//Looper退出时会调用MessageQueue的quit设置mQuitting为true
if (mQuitting) {
IllegalStateException e = new IllegalStateException(
msg.target + " sending message to a Handler on a dead thread");
Log.w(TAG, e.getMessage(), e);
msg.recycle();
return false;
}
msg.markInUse();
msg.when = when;
Message p = mMessages;
boolean needWake;
if (p == null || when == 0 || when < p.when) {
// New head, wake up the event queue if blocked.
msg.next = p;
mMessages = msg;
needWake = mBlocked;
} else {
// 插入队列中间。通常我们不必唤醒事件队列,除非队列的头部有一个barrier(同步屏障),并且该消息是队列中最早的异步消息。
needWake = mBlocked && p.target == null && msg.isAsynchronous();
Message prev;
for (;;) {
prev = p;
p = p.next;
if (p == null || when < p.when) {
break;
}
if (needWake && p.isAsynchronous()) {
needWake = false;
}
}
msg.next = p; // invariant: p == prev.next
prev.next = msg;
}
// We can assume mPtr != 0 because mQuitting is false.
//在这里如果当前的Looper是需要唤醒的,这里会执行
if (needWake) {
nativeWake(mPtr);
}
}
return true;
}
到这里Message已经到放入到MessageQueue中了,那么又是如何把消息取出来的并回掉给Handler中的handleMessage(Message msg)方法的呢?
4.Handle.handleMessage()的回调
前面我们已经看到,Handler需要在必须在Looper的环境中
public static void loop() {
final Looper me = myLooper();
//判断是否还没有启动Looper
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
//判断是否重复启动Looper
if (me.mInLoop) {
Slog.w(TAG, "Loop again would have the queued messages be executed"
+ " before this one completed.");
}
me.mInLoop = true;
// Make sure the identity of this thread is that of the local process,
// and keep track of what that identity token actually is.
Binder.clearCallingIdentity();
final long ident = Binder.clearCallingIdentity();
// Allow overriding a threshold with a system prop. e.g.
// adb shell 'setprop log.looper.1000.main.slow 1 && stop && start'
final int thresholdOverride =
SystemProperties.getInt("log.looper."
+ Process.myUid() + "."
+ Thread.currentThread().getName()
+ ".slow", 0);
me.mSlowDeliveryDetected = false;
//轮询获取MessageQueue中的message
for (;;) {
if (!loopOnce(me, ident, thresholdOverride)) {
return;
}
}
}
private static boolean loopOnce(final Looper me,
final long ident, final int thresholdOverride) {
Message msg = me.mQueue.next(); // might block
if (msg == null) {
//没有消息表示消息队列正在退出。
return false;
}
// This must be in a local variable, in case a UI event sets the logger
final Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " "
+ msg.callback + ": " + msg.what);
}
// Make sure the observer won't change while processing a transaction.
final Observer observer = sObserver;
final long traceTag = me.mTraceTag;
long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs;
long slowDeliveryThresholdMs = me.mSlowDeliveryThresholdMs;
if (thresholdOverride > 0) {
slowDispatchThresholdMs = thresholdOverride;
slowDeliveryThresholdMs = thresholdOverride;
}
final boolean logSlowDelivery = (slowDeliveryThresholdMs > 0) && (msg.when > 0);
final boolean logSlowDispatch = (slowDispatchThresholdMs > 0);
final boolean needStartTime = logSlowDelivery || logSlowDispatch;
final boolean needEndTime = logSlowDispatch;
if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
}
final long dispatchStart = needStartTime ? SystemClock.uptimeMillis() : 0;
final long dispatchEnd;
Object token = null;
if (observer != null) {
token = observer.messageDispatchStarting();
}
long origWorkSource = ThreadLocalWorkSource.setUid(msg.workSourceUid);
try {
//这里的target就是Handler,处理消息的分发
msg.target.dispatchMessage(msg);
if (observer != null) {
observer.messageDispatched(token, msg);
}
dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
} catch (Exception exception) {
if (observer != null) {
observer.dispatchingThrewException(token, msg, exception);
}
throw exception;
} finally {
ThreadLocalWorkSource.restore(origWorkSource);
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
if (logSlowDelivery) {
if (me.mSlowDeliveryDetected) {
if ((dispatchStart - msg.when) <= 10) {
Slog.w(TAG, "Drained");
me.mSlowDeliveryDetected = false;
}
} else {
if (showSlowLog(slowDeliveryThresholdMs, msg.when, dispatchStart, "delivery",
msg)) {
// Once we write a slow delivery log, suppress until the queue drains.
me.mSlowDeliveryDetected = true;
}
}
}
if (logSlowDispatch) {
showSlowLog(slowDispatchThresholdMs, dispatchStart, dispatchEnd, "dispatch", msg);
}
if (logging != null) {
logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
}
// Make sure that during the course of dispatching the
// identity of the thread wasn't corrupted.
final long newIdent = Binder.clearCallingIdentity();
if (ident != newIdent) {
Log.wtf(TAG, "Thread identity changed from 0x"
+ Long.toHexString(ident) + " to 0x"
+ Long.toHexString(newIdent) + " while dispatching to "
+ msg.target.getClass().getName() + " "
+ msg.callback + " what=" + msg.what);
}
//消息回收
msg.recycleUnchecked();
return true;
}
这里我们首先要看一下MessageQueue中的next怎么获取消息的
Message next() {
//如果消息循环已经退出并被处理,则返回此处。如果应用程序在退出后尝试重新启动不受支持的 Looper,就会发生这种情况。
final long ptr = mPtr;
if (ptr == 0) {
return null;
}
int pendingIdleHandlerCount = -1; // -1 only during first iteration
int nextPollTimeoutMillis = 0;
for (;;) {
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();
}
nativePollOnce(ptr, nextPollTimeoutMillis);
synchronized (this) {
// Try to retrieve the next message. Return if found.
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;
//查找同步屏障的消息
if (msg != null && msg.target == null) {
// Stalled by a barrier. Find the next asynchronous message in the queue.
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
if (msg != null) {
if (now < msg.when) {
//下一条消息未准备好。设置超时以在准备好时唤醒。
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
} else {
// Got a message.
mBlocked = false;
if (prevMsg != null) {
prevMsg.next = msg.next;
} else {
mMessages = msg.next;
}
msg.next = null;
if (DEBUG) Log.v(TAG, "Returning message: " + msg);
msg.markInUse();
//这里返回当前需要处理的消息
return msg;
}
} else {
// No more messages.
nextPollTimeoutMillis = -1;
}
//现在处理退出消息,所有挂起的消息都已处理完毕。
if (mQuitting) {
dispose();
return null;
}
// 如果第一次空闲,则获取要运行的空闲程序的数量。空闲句柄仅在队列为空或队列中的第一条消息(可能是障碍)将在未来处理时运行。
if (pendingIdleHandlerCount < 0
&& (mMessages == null || now < mMessages.when)) {
pendingIdleHandlerCount = mIdleHandlers.size();
}
if (pendingIdleHandlerCount <= 0) {
// No idle handlers to run. Loop and wait some more.
mBlocked = true;
continue;
}
if (mPendingIdleHandlers == null) {
mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
}
mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
}
// Run the idle handlers.
// We only ever reach this code block during the first iteration.
for (int i = 0; i < pendingIdleHandlerCount; i++) {
final IdleHandler idler = mPendingIdleHandlers[i];
mPendingIdleHandlers[i] = null; // release the reference to the handler
boolean keep = false;
try {
keep = idler.queueIdle();
} catch (Throwable t) {
Log.wtf(TAG, "IdleHandler threw exception", t);
}
if (!keep) {
synchronized (this) {
mIdleHandlers.remove(idler);
}
}
}
// Reset the idle handler count to 0 so we do not run them again.
pendingIdleHandlerCount = 0;
// While calling an idle handler, a new message could have been delivered
// so go back and look again for a pending message without waiting.
nextPollTimeoutMillis = 0;
}
}
在获取到消息之后,在Looper中的loopOnce方法里 msg.target.dispatchMessage(msg);,其中Message的Target就是Handler
public void dispatchMessage(@NonNull Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
//handleMessage被调用了
handleMessage(msg);
}
}
到这一步整个流程串起来了,但是有两个问题
- 1.当消息队列没有消息的时候,Looper是处于什么样的状态,因为它是一个循环操作,会阻塞线程?
- 2.当队列中第一个消息的触发时间还没到的话,又是怎么处理的?
这个两个问题我们都可以从MessageQueue中的next()方法中找到答案:
Message next() {
// Return here if the message loop has already quit and been disposed.
// This can happen if the application tries to restart a looper after quit
// which is not supported.
final long ptr = mPtr;
if (ptr == 0) {
return null;
}
int pendingIdleHandlerCount = -1; // -1 only during first iteration
int nextPollTimeoutMillis = 0;
for (;;) {
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();
}
//nextPollTimeoutMillis就是下一个任务需要等待执行的时间,如果nextPollTimeoutMillis为-1,那么这个Looper会一直休眠等待下去,所以子线程中的Looper没有消息要处理了要及时调用quite
nativePollOnce(ptr, nextPollTimeoutMillis);
synchronized (this) {
// Try to retrieve the next message. Return if found.
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;
if (msg != null && msg.target == null) {
// Stalled by a barrier. Find the next asynchronous message in the queue.
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
if (msg != null) {
if (now < msg.when) {
//获取到的消息没有到执行的时间,获取一个执行时间差
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
} else {
// Got a message.
mBlocked = false;
if (prevMsg != null) {
prevMsg.next = msg.next;
} else {
mMessages = msg.next;
}
msg.next = null;
if (DEBUG) Log.v(TAG, "Returning message: " + msg);
msg.markInUse();
return msg;
}
} else {
//这里就是消息队列中没有消息了
nextPollTimeoutMillis = -1;
}
// 只有调用quite之后mQuitting才为true
if (mQuitting) {
dispose();
return null;
}
// If first time idle, then get the number of idlers to run.
// Idle handles only run if the queue is empty or if the first message
// in the queue (possibly a barrier) is due to be handled in the future.
if (pendingIdleHandlerCount < 0
&& (mMessages == null || now < mMessages.when)) {
pendingIdleHandlerCount = mIdleHandlers.size();
}
//在这里跳到下一个循环,looper就开始等待了
if (pendingIdleHandlerCount <= 0) {
// No idle handlers to run. Loop and wait some more.
mBlocked = true;
continue;
}
if (mPendingIdleHandlers == null) {
mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
}
mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
}
// Run the idle handlers.
// We only ever reach this code block during the first iteration.
for (int i = 0; i < pendingIdleHandlerCount; i++) {
final IdleHandler idler = mPendingIdleHandlers[i];
mPendingIdleHandlers[i] = null; // release the reference to the handler
boolean keep = false;
try {
keep = idler.queueIdle();
} catch (Throwable t) {
Log.wtf(TAG, "IdleHandler threw exception", t);
}
if (!keep) {
synchronized (this) {
mIdleHandlers.remove(idler);
}
}
}
// Reset the idle handler count to 0 so we do not run them again.
pendingIdleHandlerCount = 0;
// While calling an idle handler, a new message could have been delivered
// so go back and look again for a pending message without waiting.
nextPollTimeoutMillis = 0;
}
}
到这里我们也就是可以知道为什么Handler能够把我们在子线程发的消息转换到主线程来了,handler线程间通信是通过共享内存实现的,内存是不分线程的,但是函数是有线程区分的,当我们在子线程通过handler.sendMessage(msg)-》MessageQueue.equeueMessage(msg)这个就是子线程操作并在MessageQueue管理的内存空间中写入一个对象数据
而在主线程中的Looper不断的轮询消息队列的方法loop是执行在主线程的,它不断的在主线程中从MessageQueue中拿消息,这样就完成了线程切换。
5.那么在Looper是如何保证在线程的唯一性?
ThreadLocal 可以进行线程数据隔离,每个线程都有单独的一个副本
每个线程都只会有一个Looper,它就是通过ThreadLocal来进行实现的
Looper相关的源码:
public final class Looper {
//ThreadLocal只有有一个,并且Looper的构造方法私有化,那么只能通过prepare()方法来进行调用
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
/**
将当前线程初始化为循环程序。 这使您有机会创建处理程序,然后在实际开始循环之前引用此循环程序。 调用此方法后一定要调用loop() ,并通过调用quit()结束它。
*/
public static void prepare() {
prepare(true);
}
private static void prepare(boolean quitAllowed) {
//首先检查当前是否已经有Looper,有那么就抛出异常,从而保证了一个线程只有一个Looper
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
}
ThreadLocal:
/**
将此线程局部变量的当前线程副本设置为指定值。 大多数子类将不需要覆盖此方法,仅依赖于initialValue方法来设置线程initialValue的值。
参数:
value -- 要存储在此线程本地的当前线程副本中的值。
*/
public void set(T value) {
//获取当前线程
Thread t = Thread.currentThread();
//通过线程获取ThreadLocalMap
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
6.同步屏障
在Android中Handler的同步屏障实现方式,是在需要的地方往消息队列中插入一条target为null的Message,根据前面的源码分析可以看到正常的消息的target就是要处理消息的Handler,在MessageQueue的next方法中,会判断当前消息。
同步屏障消息的触发:
/**
向循环程序的消息队列发送一个同步障碍。在消息队列遇到已发布的同步障碍之前,消息处理照常进行。
当遇到barrier时,队列中稍后的同步消息将被暂停(阻止执行),直到barrier通过调用removeSyncBarrier并指定标识同步barrier的令牌被释放。
此方法用于立即推迟所有随后发布的同步消息的执行,直到满足释放barrier的条件。
异步消息(请参见消息。isAsynchronous不受此障碍的限制,并照常进行处理。
该调用必须始终与removeSyncBarrier调用匹配,以确保消息队列恢复正常操作。
否则,应用程序可能会挂起!
*/
public int postSyncBarrier() {
return postSyncBarrier(SystemClock.uptimeMillis());
}
private int postSyncBarrier(long when) {
// 加入一个新的同步障碍令牌。
//我们不需要唤醒队列,因为屏障的目的是让它停滞。
synchronized (this) {
final int token = mNextBarrierToken++;
//创建一个target为null的Message
final Message msg = Message.obtain();
msg.markInUse();
msg.when = when;
msg.arg1 = token;
Message prev = null;
Message p = mMessages;
if (when != 0) {
while (p != null && p.when <= when) {
prev = p;
p = p.next;
}
}
if (prev != null) { // invariant: p == prev.next
msg.next = p;
prev.next = msg;
} else {
msg.next = p;
mMessages = msg;
}
return token;
}
}
同步屏障释放:
public void removeSyncBarrier(int token) {
//从队列中删除同步障碍令牌。
//如果队列不再被障碍物阻碍,那么唤醒它。
synchronized (this) {
Message prev = null;
Message p = mMessages;
while (p != null && (p.target != null || p.arg1 != token)) {
prev = p;
p = p.next;
}
if (p == null) {
throw new IllegalStateException("The specified message queue synchronization "
+ " barrier token has not been posted or has already been removed.");
}
final boolean needWake;
if (prev != null) {
prev.next = p.next;
needWake = false;
} else {
mMessages = p.next;
needWake = mMessages == null || mMessages.target != null;
}
p.recycleUnchecked();
//如果循环退出,那么它已经醒了。
//当mquit为false时,我们可以假设mPtr != 0。
if (needWake && !mQuitting) {
nativeWake(mPtr);
}
}
}
同步屏障在消息队列中的处理,当获取到同步屏障消息后这个消息会一直在,当下次循环的时候,我们获得还是同步屏障的消息,然后继续查找异步的消息进行处理,直到调用移除同步屏障消息:
//被障碍阻碍了。在队列中查找下一个异步消息。
if (msg != null && msg.target == null) {
// Stalled by a barrier. Find the next asynchronous message in the queue.
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
应用场景,最常见的就是屏幕刷新,屏幕刷新必然是要实时响应的,队列中这时候其他消息都要先被同步屏障挡掉,处理界面刷新的异步消息。
在ViewRootImpl中的scheduleTraversals()
void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
//先发送了同步屏障消息
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
//视图
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
if (!mUnbufferedInputDispatch) {
scheduleConsumeBatchedInput();
}
notifyRendererOfFramePending();
pokeDrawLockIfNeeded();
}
}
void doTraversal() {
if (mTraversalScheduled) {
mTraversalScheduled = false;
//移除同步屏障
mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
if (mProfile) {
Debug.startMethodTracing("ViewAncestor");
}
//循环包括performMeasure,performLayout,performDraw
performTraversals();
if (mProfile) {
Debug.stopMethodTracing();
mProfile = false;
}
}
}
7.面试问题回答
- 1.一个线程有几个Handler?
任意个,handler是new出来的 - 2.一个线程有几个looper,如何保证的?
只有一个,保障机制Looper的构建和ThreadLocal一起 - 3.Handler内存泄漏原因?为什么其他的内部类没有说过这个问题?
内存泄漏发送主要就是因为生命周期不一致的问题,Handler中容易持有外部类的引用,并且Message又会持有Handler,当Message没有回收时,根据可达性分析,这一系列的对象都无法被回收,也就发生内存泄漏了。 - 4.为何主线程可以new Handler?如果想要在子线程中new handler要做什么准备
在主线程中一创建就构建好了Looper了,但是子线程中没有,所有需要调用Looper.prepare()构建Looper,调用Looper.loop()启动Looper - 5.子线程中维护的Looper,消息队列无消息的时候处理方案是什么?有什么用?
需要调用quit()方法来退出MessageQueue的循环,返回一个为null的Message - 6.既然可以存在多个Handler往MessageQueue中添加数据(发消息时各个Handler可能处于不同线程),那它内部是如何保证线程安全的?
通过synchronized关键字包裹代码块实现,一个线程中只会有一个MessageQueue,所以在通过synchronized(this)加锁的代码(加入队列,取出,退出)的操作,同一时间只能由一个线程可以执行。 - 7.我们使用Message时应该如何创建它?
Message.obtain(),这是从消息的全量池中返回一个新的Message对象,避免分配新对象 - 8.Looper死循环为什么不会导致应用卡死?
其实这是两个概念的消息,整个应用的处理就是建立在Handler机制上的,所有的事件(点击,页面刷新等)都是通过消息机制完成的。 - 9.MessageQueue队列处理机制,在fragment生命周期管理中的应用
这个是要在事件场景去去看,例如Glide的依赖Fragment来提供对应生命周期的,在Glide中会提供一个SupportRequestMananagerFragment,一个无视图的Fragment用来安全存储RequestManager,可以用来启动、停止和管理针对Fragment或activity的目标发起的Glide请求。
final Map<FragmentManager, SupportRequestManagerFragment> pendingSupportRequestManagerFragments =
new HashMap<>();
@NonNull
private SupportRequestManagerFragment getSupportRequestManagerFragment(
@NonNull final FragmentManager fm, @Nullable Fragment parentHint, boolean isParentVisible) {
//先通过FragmentManager查找对应tag的SupportRequestManagerFragment
SupportRequestManagerFragment current =
(SupportRequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
if (current == null) {
//在map中去查找对应的SupportRequestManagerFragment
current = pendingSupportRequestManagerFragments.get(fm);
if (current == null) {
//都为说明没有创建过
current = new SupportRequestManagerFragment();
current.setParentFragmentHint(parentHint);
if (isParentVisible) {
current.getGlideLifecycle().onStart();
}
//存入map中
pendingSupportRequestManagerFragments.put(fm, current);
//启动事物创建Fragment,内部通过handler发送消息
fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
//发送消息,这里的Handler创建的是主线程的Handler,和事物当中的在同一个线程中,那么
//它们的消息队列是同一个,也就是当这个消息执行的时候,那么Fragment必然已经被创建完成了,
//那么清除Map中的就没有问题了,避免了重复创建的问题。
handler.obtainMessage(ID_REMOVE_SUPPORT_FRAGMENT_MANAGER, fm).sendToTarget();
}
}
return current;
}
/**
RequestManagerRetriever中的handleMessage
*/
@Override
public boolean handleMessage(Message message) {
boolean handled = true;
Object removed = null;
Object key = null;
switch (message.what) {
case ID_REMOVE_FRAGMENT_MANAGER:
android.app.FragmentManager fm = (android.app.FragmentManager) message.obj;
key = fm;
removed = pendingRequestManagerFragments.remove(fm);
break;
case ID_REMOVE_SUPPORT_FRAGMENT_MANAGER:
FragmentManager supportFm = (FragmentManager) message.obj;
key = supportFm;
//移除对应的Fragment
removed = pendingSupportRequestManagerFragments.remove(supportFm);
break;
default:
handled = false;
break;
}
if (handled && removed == null && Log.isLoggable(TAG, Log.WARN)) {
Log.w(TAG, "Failed to remove expected request manager fragment, manager: " + key);
}
return handled;
}