android主线程中Looper.loop()为什么不会造成程序ANR
16lz
2021-12-04
程序入口为ActivityThread的main方法,源码如下:
frameworks/base/core/java/android/app/ActivityThread.java
public static void main(String[] args) { SamplingProfilerIntegration.start(); // CloseGuard defaults to true and can be quite spammy. We // disable it here, but selectively enable it later (via // StrictMode) on debug builds, but using DropBox, not logs. CloseGuard.setEnabled(false); Environment.initForCurrentUser(); // Set the reporter for event logging in libcore EventLogger.setReporter(new EventLoggingReporter()); Security.addProvider(new AndroidKeyStoreProvider()); Process.setArgV0(""); Looper.prepareMainLooper(); ActivityThread thread = new ActivityThread(); thread.attach(false); if (sMainThreadHandler == null) { sMainThreadHandler = thread.getHandler(); } AsyncTask.init(); if (false) { Looper.myLooper().setMessageLogging(new LogPrinter(Log.DEBUG, "ActivityThread")); } Looper.loop(); throw new RuntimeException("Main thread loop unexpectedly exited"); }
可以看到main方法的最下面有调用Looper.loop()方法,我们看下Looper.loop()方法,源码如下:
frameworks/base/core/java/android/os/Looper.java
/** * Run the message queue in this thread. Be sure to call * {@link #quit()} to end the loop. */ public static void loop() { final Looper me = myLooper(); if (me == null) { throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread."); } final MessageQueue queue = me.mQueue; // 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(); for (;;) { Message msg = queue.next(); // might block if (msg == null) { // No message indicates that the message queue is quitting. return; } // This must be in a local variable, in case a UI event sets the logger Printer logging = me.mLogging; if (logging != null) { logging.println(">>>>> Dispatching to " + msg.target + " " + msg.callback + ": " + msg.what); } msg.target.dispatchMessage(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.recycle(); } }
可以看到looper方法中有个for死循环中next方法是阻塞的,那么为什么这里阻塞不会造成主线程卡死然后ANR呢?参考了好多资料都比较抽象难懂,这里自己用“土方子”从反面考虑这个问题
- 写了一个demo,点击按钮执行如下代码
Looper.getMainLooper().quit();
退出looper后,handler发送的所有消息都会失败,同时这个UI线程就会立刻终止;测试了下点击按钮,这个app会立刻关闭;ActivityThread的main方法主要功能就是做消息循环,必须一直存在,一旦退出消息循环,app就会立刻关闭;
- 那为什么阻塞还可以和主线程进行交互呢?
仔细观察ActivityThread中的main方法中Looper.loop();在方法的最后位置,放在main方法?如果在其后面再添加东西那么肯定不会执行。那我理解的是main方法中Looper.loop()这句前所有的UI交互逻辑应该都在这一部分,这一部分是不会受到loop()方法阻塞影响;并且阻塞不代表不运行,只是等待状态;在ActivityThread类中的内部类H继承Handler,里面实现了不同的消息处理的case,只要通过handler发送消息,messagequeue中有message,只要保证有消息的时候能够立刻处理,程序是不会无响应的
frameworks/base/core/java/android/app/ActivityThread.java
private class H extends Handler { public static final int LAUNCH_ACTIVITY = 100; public static final int PAUSE_ACTIVITY = 101; public static final int PAUSE_ACTIVITY_FINISHING= 102; public static final int STOP_ACTIVITY_SHOW = 103; public static final int STOP_ACTIVITY_HIDE = 104; public static final int SHOW_WINDOW = 105; public static final int HIDE_WINDOW = 106; public static final int RESUME_ACTIVITY = 107; public static final int SEND_RESULT = 108; public static final int DESTROY_ACTIVITY = 109; public static final int BIND_APPLICATION = 110; public static final int EXIT_APPLICATION = 111; public static final int NEW_INTENT = 112; public static final int RECEIVER = 113; public static final int CREATE_SERVICE = 114; public static final int SERVICE_ARGS = 115; public static final int STOP_SERVICE = 116; public static final int REQUEST_THUMBNAIL = 117; public static final int CONFIGURATION_CHANGED = 118; public static final int CLEAN_UP_CONTEXT = 119; public static final int GC_WHEN_IDLE = 120; public static final int BIND_SERVICE = 121; public static final int UNBIND_SERVICE = 122; public static final int DUMP_SERVICE = 123; public static final int LOW_MEMORY = 124; public static final int ACTIVITY_CONFIGURATION_CHANGED = 125; public static final int RELAUNCH_ACTIVITY = 126; public static final int PROFILER_CONTROL = 127; public static final int CREATE_BACKUP_AGENT = 128; public static final int DESTROY_BACKUP_AGENT = 129; public static final int SUICIDE = 130; public static final int REMOVE_PROVIDER = 131; public static final int ENABLE_JIT = 132; public static final int DISPATCH_PACKAGE_BROADCAST = 133; public static final int SCHEDULE_CRASH = 134; public static final int DUMP_HEAP = 135; public static final int DUMP_ACTIVITY = 136; public static final int SLEEPING = 137; public static final int SET_CORE_SETTINGS = 138; public static final int UPDATE_PACKAGE_COMPATIBILITY_INFO = 139; public static final int TRIM_MEMORY = 140; public static final int DUMP_PROVIDER = 141; public static final int UNSTABLE_PROVIDER_DIED = 142; public static final int REQUEST_ASSIST_CONTEXT_EXTRAS = 143; public static final int TRANSLUCENT_CONVERSION_COMPLETE = 144; public static final int INSTALL_PROVIDER = 145; String codeToString(int code) { if (DEBUG_MESSAGES) { switch (code) { case LAUNCH_ACTIVITY: return "LAUNCH_ACTIVITY"; case PAUSE_ACTIVITY: return "PAUSE_ACTIVITY"; case PAUSE_ACTIVITY_FINISHING: return "PAUSE_ACTIVITY_FINISHING"; case STOP_ACTIVITY_SHOW: return "STOP_ACTIVITY_SHOW"; case STOP_ACTIVITY_HIDE: return "STOP_ACTIVITY_HIDE"; case SHOW_WINDOW: return "SHOW_WINDOW"; case HIDE_WINDOW: return "HIDE_WINDOW"; case RESUME_ACTIVITY: return "RESUME_ACTIVITY"; case SEND_RESULT: return "SEND_RESULT"; case DESTROY_ACTIVITY: return "DESTROY_ACTIVITY"; case BIND_APPLICATION: return "BIND_APPLICATION"; case EXIT_APPLICATION: return "EXIT_APPLICATION"; case NEW_INTENT: return "NEW_INTENT"; case RECEIVER: return "RECEIVER"; case CREATE_SERVICE: return "CREATE_SERVICE"; case SERVICE_ARGS: return "SERVICE_ARGS"; case STOP_SERVICE: return "STOP_SERVICE"; case REQUEST_THUMBNAIL: return "REQUEST_THUMBNAIL"; case CONFIGURATION_CHANGED: return "CONFIGURATION_CHANGED"; case CLEAN_UP_CONTEXT: return "CLEAN_UP_CONTEXT"; case GC_WHEN_IDLE: return "GC_WHEN_IDLE"; case BIND_SERVICE: return "BIND_SERVICE"; case UNBIND_SERVICE: return "UNBIND_SERVICE"; case DUMP_SERVICE: return "DUMP_SERVICE"; case LOW_MEMORY: return "LOW_MEMORY"; case ACTIVITY_CONFIGURATION_CHANGED: return "ACTIVITY_CONFIGURATION_CHANGED"; case RELAUNCH_ACTIVITY: return "RELAUNCH_ACTIVITY"; case PROFILER_CONTROL: return "PROFILER_CONTROL"; case CREATE_BACKUP_AGENT: return "CREATE_BACKUP_AGENT"; case DESTROY_BACKUP_AGENT: return "DESTROY_BACKUP_AGENT"; case SUICIDE: return "SUICIDE"; case REMOVE_PROVIDER: return "REMOVE_PROVIDER"; case ENABLE_JIT: return "ENABLE_JIT"; case DISPATCH_PACKAGE_BROADCAST: return "DISPATCH_PACKAGE_BROADCAST"; case SCHEDULE_CRASH: return "SCHEDULE_CRASH"; case DUMP_HEAP: return "DUMP_HEAP"; case DUMP_ACTIVITY: return "DUMP_ACTIVITY"; case SLEEPING: return "SLEEPING"; case SET_CORE_SETTINGS: return "SET_CORE_SETTINGS"; case UPDATE_PACKAGE_COMPATIBILITY_INFO: return "UPDATE_PACKAGE_COMPATIBILITY_INFO"; case TRIM_MEMORY: return "TRIM_MEMORY"; case DUMP_PROVIDER: return "DUMP_PROVIDER"; case UNSTABLE_PROVIDER_DIED: return "UNSTABLE_PROVIDER_DIED"; case REQUEST_ASSIST_CONTEXT_EXTRAS: return "REQUEST_ASSIST_CONTEXT_EXTRAS"; case TRANSLUCENT_CONVERSION_COMPLETE: return "TRANSLUCENT_CONVERSION_COMPLETE"; case INSTALL_PROVIDER: return "INSTALL_PROVIDER"; } } return Integer.toString(code); } 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"); 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 != 0, msg.arg2); 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 != 0, msg.arg2); 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 REQUEST_THUMBNAIL: Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "requestThumbnail"); handleRequestThumbnail((IBinder)msg.obj); 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, (ProfilerControlData)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; } if (DEBUG_MESSAGES) Slog.v(TAG, "<<< done: " + codeToString(msg.what)); }
纯属个人理解,其他参考资料见下面链接
知乎-Android中为什么主线程不会因为Looper.loop()里的死循环卡死?
Looper.loop()一直死循环
Android中为什么主线程不会因为Looper.loop()里的死循环阻塞?
更多相关文章
- Android强制设置横屏或竖屏
- Android获取状态栏高度的方法
- android-使App全屏 - 随心
- android中遍历arrayList的四种方法
- android实现猜扑克牌小游戏(改进:每次只可以选择一张)
- Glide使用方法汇总
- 【android】对canvas的translate(),save(),restore()方法的理解
- Android(安卓)Jetpack之Lifecycle的源码分析
- Android性能检测--traceview工具各个参数的意思