android之handler使用與原理
下面的是個人對handler的一些感想,忘能幫助初學者
handler是什麼
handler是android系統提供的一套訊息機制的上層介面,使用handler可以輕鬆地切換任務執行緒那它可以用來幹嘛呢。
當需要在子執行緒中進行耗時的I/O操作的時候,當耗時任務完成以後,需要在UI上做一些改變,但是在子執行緒不能訪問handler這時就要使用handler。要記住一點,handler不是專門用來更新UI的。
接下來介紹幾個概念。
MessageQueue
它是用來儲存訊息的,注意它是單鏈表的資料結構。
Looper
訊息迴圈者,用來取MessageQueue的訊息並處理,沒訊息阻塞。
好了,接下來慢慢介紹。
不知大家注意到了沒子執行緒訪問UI會報異常,這是因為不能再子執行緒更新UI,那麼android是怎麼確定的呢,因為ViewRootImpl會對UI操作進行驗證,是由ViewRootImpl的checkThread來完成的。因此大家也別想著用什麼辦法繞過了,因為系統已經強制規定了。
Handler在建立的時候會用當前執行緒的Looper來構建訊息迴圈系統,因此在子執行緒中直接使用Handler會報錯,因為子執行緒是沒有Looper的,那UI執行緒有沒有呢,UI執行緒會在ActivityThread建立UI執行緒的時候初始化一個Looper,這也是主執行緒可以使用handler的原因,要在子執行緒使用handler,要先出初始化Looper,呼叫Looper.perpar()即可當呼叫handler的send方法時,它會呼叫MessageQueue的enqueueMessage()方法將訊息放到佇列中去,Looper發現有新訊息時會處理訊息,最終訊息中的Runnable或者handler的handleMessage會呼叫。
這裡要知道Looper是儲存在ThreadLocal中的,它是一個作用域為當前執行緒的儲存類。底下是個例子
public class TestHandlerActivity extends AppCompatActivity {
private static final String TAG = "TestHandlerActivity";
private Handler mHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
//獲得剛才傳送的Message物件,然後在這裡進行UI操作
Log.e(TAG,"------------> msg.what = " + msg.what);
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_handler_test);
initData();
}
private void initData() {
//開啟一個執行緒模擬處理耗時的操作
new Thread(new Runnable() {
@Override
public void run() {
SystemClock.sleep(2000);
//通過Handler傳送一個訊息切換回主執行緒(mHandler所在的執行緒)
mHandler.sendEmptyMessage(0);
}
}).start();
}
這是一個很簡單的例子,接下來再看用post方法傳送已個Runnable介面的方法。
public class MainActivity extends Activity {
private TextView text_view = null;
private Button start = null;
private Button end = null;
//使用handler時首先要建立一個handler
Handler handler = new Handler();
//要用handler來處理多執行緒可以使用runnable介面,這裡先定義該介面
//執行緒中執行該介面的run函式
Runnable update_thread = new Runnable()
{
public void run()
{
//執行緒每次執行時輸出"UpdateThread..."文字,且自動換行
//textview的append功能和Qt中的append類似,不會覆蓋前面
//的內容,只是Qt中的append預設是自動換行模式
text_view.append("\nUpdateThread...");
//延時1s後又將執行緒加入到執行緒佇列中
handler.postDelayed(update_thread, 1000);
}
};
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
text_view = (TextView)findViewById(R.id.text_view);
start = (Button)findViewById(R.id.start);
start.setOnClickListener(new StartClickListener());
end = (Button)findViewById(R.id.end);
end.setOnClickListener(new EndClickListener());
}
private class StartClickListener implements OnClickListener
{
public void onClick(View v) {
// TODO Auto-generated method stub
//將執行緒介面立刻送到執行緒佇列中
handler.post(update_thread);
}
}
private class EndClickListener implements OnClickListener
{
public void onClick(View v) {
// TODO Auto-generated method stub
//將介面從執行緒佇列中移除
handler.removeCallbacks(update_thread);
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}
}
接下來各自分析一下
MessageQueue
它主要用來儲存訊息,有兩個基本操作,插入和讀取,讀取操作會伴隨著刪除操作,當Handler傳送一條訊息時會呼叫他的enqueueMessage方法插入訊息,此時有了一條訊息,接著它會呼叫自身的next方法讀取訊息並從佇列中(資料結構是單鏈表)刪除訊息,接著Looper發現有訊息就會把它交給handler去處理,handler呼叫自身的handlermessage()方法,這裡要注意我們可以通過getMainLooper()得到UI現成的Looper,當在子執行緒建立Looper不用的時候要呼叫他的quitsafely()方法,否則Looper會一直阻塞。
好了,這就是訊息處理機制了。