1. 程式人生 > >android之handler使用與原理

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會一直阻塞。
好了,這就是訊息處理機制了。