|
作者:@JohnTsai Android進階——深入淺出Handler(一)在學習Handler之前,首先要學習一些基本概念,這將對之后的學習有所幫助。
下面用代碼來解釋什么是主線程和ANR:
初識Handler首先我們通過一個Demo學習Handler的兩種基本用途:
第一種用途比較好理解,比如延時finish掉啟動Activity。第二種是我們在經(jīng)常需要子線程中執(zhí)行耗時操作,可能是讀取文件或訪問網(wǎng)絡,但是我們只能在主線程中更新UI。所以使用Handler來將更新UI的操作從子線程切換到主線程中執(zhí)行。 1.繼承Handler類,實現(xiàn)handleMessage方法。一般不推薦使用非靜態(tài)內(nèi)部類的方式實現(xiàn),會導致內(nèi)存泄露。具體原因可參看我上一篇文章,Android開發(fā)——避免內(nèi)存泄露。推薦使用靜態(tài)內(nèi)部類和弱引用結(jié)合的方式來實現(xiàn)。如下所示。 private static class MyHandler extends Handler{
//對Activity的弱引用
private final WeakReference<HandlerActivity> mActivity;
public MyHandler(HandlerActivity activity){
mActivity = new WeakReference<HandlerActivity>(activity);
}
@Override
public void handleMessage(Message msg) {
HandlerActivity activity = mActivity.get();
if(activity==null){
super.handleMessage(msg);
return;
}
switch (msg.what) {
case DOWNLOAD_FAILED:
Toast.makeText(activity, "下載失敗", Toast.LENGTH_SHORT).show();
break;
case DOWNLOAD_SUCCESS:
Toast.makeText(activity, "下載成功", Toast.LENGTH_SHORT).show();
Bitmap bitmap = (Bitmap) msg.obj;
activity.imageView.setVisibility(View.VISIBLE);
activity.imageView.setImageBitmap(bitmap);
break;
default:
super.handleMessage(msg);
break;
}
}
}
private final MyHandler mHandler = new MyHandler(this);2.使用post方法發(fā)送Runnable對象,sendMessage方法來發(fā)送Message。 下面的代碼通過postDelayed執(zhí)行1秒后將Button顯示或隱藏的操作。在下載完圖片后使用sendMessage通知UI線程更新ImageView。 //使用Handler進行延時操作
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
imageView.setVisibility(imageView.getVisibility()==View.VISIBLE?View.GONE:View.VISIBLE);
}
},1000);
//使用子線程下載圖片
new Thread(new Runnable() {
@Override
public void run() {
Bitmap bitmap = downloadImage();
Message msg = Message.obtain();
msg.obj = bitmap;
msg.what = bitmap==null?DOWNLOAD_FAILED:DOWNLOAD_SUCCESS;
handler.sendMessage(msg);
}
}).start(); 運行效果:
進一步了解Handler說起Handler,就不得不提Message、MessageQueue以及Looper。搞清楚這四者之間的關系,Android開發(fā)中的Handler消息處理機制也掌握了個大概了。 MessageMessage:包含描述和任意數(shù)據(jù)對象的消息,用于發(fā)送給Handler。 學到這里,可能有人會有疑問。不是可通過Handler發(fā)送Runnable對象的嗎?為什么這里只提Message了呢? 好問題,讓我們來查看post類方法的源碼。 在postDelayed()方法內(nèi)部,將Runnable對象通過getPostMessage()方法包裝成了一個Message對象。這樣就回答了我們之前的疑問。對于Handler,不管是使用的是post類方法還是send類方法,發(fā)送出去的都是Message對象。 Message類中有這幾個成員變量描述消息,其中what是我們定義的消息碼,為了讓接收者能知道消息是關于什么的。arg1和arg2用于發(fā)送一些integer類型的值。obj用于傳輸任意類型的值。 MessageQueueMessageQueue:顧名思義,消息隊列。內(nèi)部存儲著一組消息。對外提供了插入和刪除的操作。MessageQueue內(nèi)部是以單鏈表的數(shù)據(jù)結(jié)構(gòu)來存儲消息列表的。 獲取MessageQueue實例使用Looper.myQueue()方法。 查看源碼中的enqueueMessage()方法能看出MessageQueue是用單鏈表的數(shù)據(jù)結(jié)構(gòu)來存儲消息的。 LooperLooper:主要用于給一個線程輪詢消息的。線程默認沒有Looper,在創(chuàng)建Handler對象前,我們需要為線程創(chuàng)建Looper。 使用Looper.prepare()方法創(chuàng)建Looper,使用Looper.loop()方法運行消息隊列。 這里就有疑問了,之前我們在主線程中,創(chuàng)建Handler之前并沒有創(chuàng)建Looper。這是為什么呢?查看Main Thread源碼(也就是ActivityThread)。 在ActivityThread的main方法中,初始化了Looper。這就是為什么我們在主線程中不需要創(chuàng)建Looper的原因。 好,今天的學習就到這。下次將繼續(xù)學習Handler、Message和Message之間的關系。 如果本文對你的開發(fā)有所幫助,并且你手頭恰好有零錢。 不如打賞我一杯咖啡,鼓勵我繼續(xù)分享優(yōu)秀的文章。 |
|
|