做用:php
四要素:git
具體流程github
注意:一個Thread只能有一個Looper,能夠有多個Handler面試
爲何一個線程只有一個Looper?技術博客大總結segmentfault
public static void prepare() { prepare(true); } 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)); }
不一樣於主線程直接new一個Handler,因爲子線程的Looper須要手動去建立,在建立Handler時須要多一些方法:安全
handler = null; new Thread(new Runnable() { private Looper mLooper; @Override public void run() { //必須調用Looper的prepare方法爲當前線程建立一個Looper對象,而後啓動循環 //prepare方法中實質是給ThreadLocal對象建立了一個Looper對象 //若是當前線程已經建立過Looper對象了,那麼會報錯 Looper.prepare(); handler = new Handler(); //獲取Looper對象 mLooper = Looper.myLooper(); //啓動消息循環 Looper.loop(); //在適當的時候退出Looper的消息循環,防止內存泄漏 mLooper.quit(); } }).start();
Looper.prepare()方法源碼分析markdown
public static void prepare() { prepare(true); } 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.prepare()可否調用兩次或者屢次數據結構
//這裏Looper.prepare()方法調用了兩次 Looper.prepare(); Looper.prepare(); Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { if (msg.what == 1) { Log.i(TAG, "在子線程中定義Handler,並接收到消息。。。"); } } }; Looper.loop();
爲何系統不建議在子線程訪問UI多線程
不對UI控件的訪問加上鎖機制的緣由併發
問題描述
ActivityThread中main方法
ActivityThread類的註釋上能夠知道這個類管理着咱們日常所說的主線程(UI線程)
public static final void main(String[] args) { ... //建立Looper和MessageQueue Looper.prepareMainLooper(); ... //輪詢器開始輪詢 Looper.loop(); ... }
Looper.loop()方法無限循環
看看Looper.loop()方法無限循環部分的代碼
while (true) { //取出消息隊列的消息,可能會阻塞 Message msg = queue.next(); // might block ... //解析消息,分發消息 msg.target.dispatchMessage(msg); ... }
爲何這個死循環不會形成ANR異常呢?
處理消息handleMessage方法
以下所示
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; ........... } }
loop的循環消耗性能嗎?
建立Message對象的幾種方式:技術博客大總結
runOnUiThread如何實現子線程更新UI
public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } } @Override public final void runOnUiThread(Runnable action) { if (Thread.currentThread() != mUiThread) { mHandler.post(action); } else { action.run(); } }
線程本地存儲的功能
怎麼存儲呢?底層數據結構是啥?