Handler,Looper,MessageQueue,ThreadLocal講解以及實例

Handler:是android消息機制的核心。一個線程可以有多個handler,但是只能有一個Looper和MessageQueue。handler是用來在線程間傳遞消息的。

而handler是發送消息以及傳遞消息的。在UI線程也是主線程,由於主線程會自動創建Looper,所以在子線程中,必須自己創建Looper才能創建Handler。

Handler的消息發送可以是handler.sendMessage()或者是handler.post(Runnable)。其中sendMessage()方法需要實現Handler的handleMessage方法,也就是消息的最終處理。

Looper是運行在創建Handler的那個線程中的。由於可以有多個handler,那麼怎麼知道消息的最終處理是交給那個handler的handleMessage中呢?

由於Message類中有個變量叫做target,message.target對應生成該message的handler,所以放在Looper處理時,就會轉到對應的handleMessage中。

MessageQueue:是消息隊列,但是它的實現是單鏈表,因爲是要刪除和添加,所以單鏈表的實現比較好,MessageQueue是由Looper.prapare()中實現的,其實也是Looper.parpare()方法調用Looper構造函數,由Looper構造函數中生成MessageQueue的。MessageQueue有兩個方法,一個是enqueueMessage(),一個是next(),enqueueMessage()方法是插入Message,next()方法是讀取一個Message,並且刪除這個Message。其中next()方法是個無限循環的方法。

Looper:Looper叫做循環,由於MessageQueue只是用來存儲Message的,而Looper則是用來處理Message的。Looper.loop()方法調用,纔開始真正啓動消息循環系統,在loop()中,會不斷的調用messagequeue的next()方法,直到next()方法返回null則會停止。而next()不會主動自己返回null的,需要調用MessageQueue的quit()方法或者quitSafely()使得MessageQueue中的next()方法返回null,使得loop()方法中斷。

ThreadLocal:不是線程,而是以線程爲作用域的,各個線程之間互不干擾的一個數據存儲類,用來存儲Looper的,其中每個線程都有一個ThreadLocal.Values的變量來存儲ThreadLocal的數據,其中是一個table數組。ThreadLocal的好處在於,1.線程之間互不干擾,否則需要設置一個通過handler查找looper的全局hash表。2.用在線程中的函數調用棧深的時候,需要在線程全程傳遞監聽器,可以在該線程中設置一個ThreadLocal的全局變量。

整個流程是:在一般的Android消息機制中,先在主線程中創建一個handler,由於這個handler是在主線程中創建的,所以對應的主線程中本身存在的Looper,在子線程的耗時操作結束以後,需要將這個數據傳遞給主線程來更新UI,那麼就直接調主線程的handler,通過handler.sendMessage()將消息插入到MessageQueue中,再由Looper來提取該消息,並處理,調用msg.target.dispatchMessage(msg),其中msg.target就是對應的handler,只是這個handler.dispatchMessage()方法是在主線程的Looper中執行的。也就實現了從子線程到主線程的傳遞。其中的MessageQueue和Looper都是主線程的。

以下是handler的實例

其中項目地址爲:點擊打開鏈接

package com.example.simmucheng.handlerdemo;

import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {

    private Button Btn_start_sendmessage=null;
    private Button Btn_start_Runable=null;
    private Button Btn_from_main_to_thread=null;
    private Button Btn_stop=null;
    private TextView Tv_showtextview=null;
    private Handler ThreadHandler;

    Handler handler_main=new Handler();
    Handler handler_main_handlemessage=new Handler(){
        @Override
        public void handleMessage(Message msg) {
           // ThreadHandler.sendMessage(msg);
            Tv_showtextview.append("sendMessage = "+msg.arg1);
        }
    };

    Runnable MyRunnable=new Runnable() {
        @Override
        public void run() {
            Tv_showtextview.append("\nloading");
            handler_main.postDelayed(MyRunnable,1000);
        }
    };
    Handler handler1=new Handler(){
        @Override
        public void handleMessage(Message msg) {
            Tv_showtextview.append("\nheihei");
            Toast.makeText(MainActivity.this,"tttttt",Toast.LENGTH_SHORT).show();
        }
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
        new MyThread().start();
        Btn_start_Runable.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                handler_main.post(MyRunnable);
            }
        });
        Btn_start_sendmessage.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                new Thread(){
                    @Override
                    public void run() {
                        Message msg=new Message();
                        msg.arg1=1;
                        msg.what=2;
                        handler1.sendMessage(msg);
                    }
                }.start();

            }
        });
        Btn_stop.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                handler_main.removeCallbacks(MyRunnable);
            }
        });
        Btn_from_main_to_thread.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Message msg1=new Message();
                msg1.arg1=3;
                ThreadHandler.sendMessage(msg1);
            }
        });
    }

    private void initView() {
        Btn_start_sendmessage= (Button) findViewById(R.id.Start_Handler_sendmessage);
        Btn_from_main_to_thread= (Button) findViewById(R.id.from_main_to_thread);
        Btn_start_Runable= (Button) findViewById(R.id.Start_Handler_Runable);
        Btn_stop= (Button) findViewById(R.id.stop);
        Tv_showtextview= (TextView) findViewById(R.id.ShowTextView);
    }

    class MyThread extends Thread{
        @Override
        public void run() {
            Looper.prepare();
            ThreadHandler=new Handler(Looper.myLooper()){
                @Override
                public void handleMessage(Message msg) {
                    msg.arg1+=1000;
                    Message msg1=handler_main_handlemessage.obtainMessage();
                    msg1.arg1=msg.arg1;
                    handler_main_handlemessage.sendMessage(msg1);
                    // 這個裏面,在sendMessage(message)之後,會標記該message的isInUse=true
                    //所以要想再次sendMessage該message,需要重新obtainMessage得到新的message,這樣
                    //得到的message的isInUse會被取消
                }
            };
            Looper.loop();
        }


    }
}

其中enqueueMessage的局部代碼,顯示會將message標記爲已經加入隊列。所以有的時候不注意會出現in use的錯誤。

boolean enqueueMessage(Message msg, long when) {
        if (msg.target == null) {
            throw new IllegalArgumentException("Message must have a target.");
        }
        if (msg.isInUse()) {
            throw new IllegalStateException(msg + " This message is already in use.");
        }

        synchronized (this) {
            if (mQuitting) {
                IllegalStateException e = new IllegalStateException(
                        msg.target + " sending message to a Handler on a dead thread");
                Log.w(TAG, e.getMessage(), e);
                msg.recycle();
                return false;
            }

            <span style="color:#ff0000;">msg.markInUse();</span>
            msg.when = when;
            Message p = mMessages;
      }
}

    /*package*/ boolean isInUse() {
        return ((flags & FLAG_IN_USE) == FLAG_IN_USE);
    }

    /*package*/ void markInUse() {
        flags |= FLAG_IN_USE;
    }


發佈了144 篇原創文章 · 獲贊 4 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章