常見用法:
- Message盡量復(fù)用,obtain從消息池中取兄春。
//消息池中取出的
public static Message obtain() {
synchronized (sPoolSync) {
if (sPool != null) {
Message m = sPool;
sPool = m.next;
m.next = null; //從sPool中取出一個Message對象澎剥,并消息鏈表斷開
m.flags = 0; // 清除in-use flag
sPoolSize--; //消息池的可用大小進行減1操作
return m;
}
}
return new Message(); // 當消息池為空時,直接創(chuàng)建Message對象
}
假如有個Runnbal包裝的Message用完以后在消息池中赶舆,obtain拿到后哑姚,設(shè)置what,obj等信息芜茵,那么現(xiàn)在這個msg有callback叙量,還有what等信息。會不會在分發(fā)的時候夕晓,calllBack != null宛乃,那又繼續(xù)調(diào)用了runnable的run方法了?并沒有達到這個msg的目的啊。
測試post的50個runnable的消息征炼,obtain取了300個新的析既,并沒有復(fù)用到runnable的。 因該是怎樣呢谆奥?
- getMainLooper()/view.post(runnable)/handler.post(runnable)
- activity.runOnUiThread
public final void runOnUiThread(Runnable action) {
if (Thread.currentThread() != mUiThread) {
//非UI線程眼坏,到handler執(zhí)行
mHandler.post(action);
} else {
//UI線程直接run
action.run();
}
}
- onCreat方法完成之前,在非UI線程更改UI不會報錯酸些。
- loop死循環(huán)宰译,后面的代碼無法執(zhí)行∑嵌可退出沿侈。
@OnClick({R.id.test_btn_1, R.id.test_btn_2})
public void onViewClicked(View view) {
switch (view.getId()) {
case R.id.test_btn_1:
new Thread(new Runnable() {
@Override
public void run() {
Looper.prepare();
handler = new TestHandler();
//打印log
handler.sendEmptyMessage(11);
Looper.loop();
//不執(zhí)行,loop死循環(huán)市栗,執(zhí)行不到
Log.e(TAG, "run: after loop" );
}
}).start();
break;
case R.id.test_btn_2:
//退出缀拭,繼續(xù)向下執(zhí)行,打印log
handler.getLooper().quit();
break;
}
}
- ActivityThread不會影響:UI線程中ActivityThread就是消息循環(huán)填帽,各種onResume/onCreate方法蛛淋,都是通過handler發(fā)送消息調(diào)用更新的,可以把這些方法的執(zhí)行看作一個個消息篡腌,如果某個消息處理實踐過程褐荷,就可能會影響UI刷新造成卡頓。(涉及到Binder/進程/Linux管道等知識嘹悼,馬達現(xiàn)在段位不夠叛甫,看不懂)
public static void main(String[] args) {
...
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");
}
- 異常方面
當 Activity finish 時,在 onDestroy 方法中釋放了一些資源。此時 Handler 執(zhí)行到 handlerMessage 方法,但相關(guān)資源已經(jīng)被釋放,從而引起空指針的異常绘迁。
避免
如果是使用 handlerMessage合溺,則在方法中加try catch。
如果是用 post 方法缀台,則在Runnable方法中加try catch。
- 內(nèi)存泄露
handler可能引用外部累對象activity哮奇,如果activity關(guān)閉膛腐,handler沒執(zhí)行完,從而引起activity內(nèi)存泄漏鼎俘。
/**
為避免handler造成的內(nèi)存泄漏
1哲身、使用靜態(tài)的handler,對外部類不保持對象的引用
2贸伐、但Handler需要與Activity通信勘天,所以需要增加一個對Activity的弱引用
*/
private static class MyHandler extends Handler {
private final WeakReference<Activity> mActivityReference;
MyHandler(Activity activity) {
this.mActivityReference = new WeakReference<Activity>(activity);
}
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
MainActivity activity = (MainActivity) mActivityReference.get(); //獲取弱引用隊列中的activity
switch (msg.what) { //獲取消息,更新UI
case 1:
byte[] data = (byte[]) msg.obj;
activity.threadIv.setImageBitmap(activity.getBitmap(data));
break;
}
}
}