相關概念
1.Handler:可以看做是一個工具類,用來向訊息佇列中插入訊息的;
2.Thread:所有與Handler相關的功能都是與Thread密不可分的,Handler會與建立時所在的線程綁定;
3.Message:訊息;
4.MessageQueue:訊息佇列,對訊息進行管理,實現了一個Message鏈表;
5.Looper:訊息迴圈,從MessageQueue中取出Message進行處理;
6.HandlerThread:繼承Thread,執行個體化時自動建立Looper對象,實現一個訊息迴圈線程.
在Android開發中經常會使用到線程,一想到線程,一般都會想到:
new Thread(){...}.start();
這樣的方式。這樣如果在一個Activity中多次調用上面的代碼,那麼將建立多個匿名線程,如果這些線程的沒有被銷毀,那肯定會影響效能呢。這個時候我麼就想到了android提供的一個非同步處理線程的類HandlerThread。
一般Handler的用法
Handler handler = new Handler(){...};
這樣建立的handler是在主線程即UI線程下的Handler,即這個Handler是與UI線程下的預設Looper綁定的(當然也只有主線程才能這麼幹,子線程是幹不了的,除非自己建立個looper)。因此,有些時候會佔用ui主線程,引起一些問題,所以我們就想到了重新建立個子線程,來處理handler。。。。
使用HandlerThread解決問題
HandlerThread實際上繼承於Thread,只不過它比普通的Thread多了一個Looper。我們可以使用下面的例子建立Handler
HandlerThread thread = new HandlerThread("MyHandlerThread");thread.start();
建立HandlerThread時要把它啟動了,即調用start()方法。
接著就是handler的使用,如下:
mHandler = new Handler(thread.getLooper());//TODO:you can post or send something....
建立Handler時將HandlerThread中的looper對象傳入。那麼這個mHandler對象就是與HandlerThread這個線程綁定了(這時就不再是與UI線程綁定了,這樣它處理耗時操作將不會阻塞UI)。
線程中訊息處理的流程圖
訊息插入隊列的位置由參數uptimeMillis來確定。
Handler與線程的關係
1.HandlerThread就是一個封裝了Looper的Thread.
2.Handler會與執行個體化時所在的線程綁定.
UI線程與子線程通訊相關
1.需要更新UI,則需要使用與主線程綁定的Handler發送訊息,若使用在子線程中建立的Handler則會拋出異常;
2.子線程中執行個體化Handler對象首先需要調用Looper.prepare(),否則會拋出異常;
3.調用Looper.loop()方法訊息迴圈才會啟動;
使用Handler時一些需要注意的地方
Looper.prepare(),主線程使用handler,系統預設prepare了,子線程中建立handler必須在前面Looper.prepare(),後面加上Looper.loop();
源碼中:
主線程:
在程式啟動的時候,系統已經幫我們自動調用了Looper.prepare()方法。查看ActivityThread中的main()
public static void main(String[] args) { SamplingProfilerIntegration.start(); CloseGuard.setEnabled(false); Environment.initForCurrentUser(); EventLogger.setReporter(new EventLoggingReporter()); Process.setArgV0("<pre-initialized>"); 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"); }
請注意Looper.prepareMainLooper():
public static final void prepareMainLooper() { prepare(); setMainLooper(myLooper()); if (Process.supportsProcesses()) { myLooper().mQueue.mQuitAllowed = false; } }
子線程:
new Thread(new Runnable() { @Override public void run() { Looper.prepare() handler2 = new Handler(); Looper.loop() } }).start();
如果沒有Looper.prepare().會報錯:
Can't create handler inside thread that has not called Looper.prepare()
因為沒looper對象建立
looper.prepare()源碼:
public static final void prepare() { if (sThreadLocal.get() != null) { throw new RuntimeException("Only one Looper may be created per thread"); } sThreadLocal.set(new Looper()); }