Android 多線程通信Handler

        在Android中應用到多線程通信,尤其是新的線程去更新主線程的UI,因爲新線程無法直接更新widget, 所以在Android多應用handler處理多線程的通信。

Handler主要有兩個作用,一是安排消息或者Runnable在某個主線程中某個地方執行,二是安排一個任務去別的線程工作。

提到Handler肯定會設計到Looper,Looper的作用就是替對應的Handler管理消息,每一個Handler都有一個屬於自己的Looper,這是一個對一的關係,在Android中除了主線程外其他線程在使用時不會自動爲handler分配Looper的,所以在新的線程應用Handler的時候必須首選Looper.prepare函數來初始化Looper,然後用loop()函數來做信息循環的處理。

MessageQueue是控制所屬線程的消息,所有的message並不是直接會存儲在MeesageQueue中,通過Looper工作的。MessageQueue, Looper

Handler三者是一對一的關係,並且他們三個和某一個所屬的線程也是一對一的關係,每個線程都有自己的一套Handler機制 。

具體的消息運行機制是Looper將發出的消息放到MessageQueue中,然後循環的傳遞給Handler,Handler會將當前的Message進行處理,然後做出相應的反應。

其實無論怎樣發送,他們的重點只是一條,用的哪個handler發送的消息,就由這個handler處理消息,這個線程所處的線程做出相應的反應。handler和thread是綁定的一對>一關係。 想讓線程接收什麼,就用線程所屬的handler發送消息。

例如子線程給主線程發送消息更新UI 和主線程給子線程發送信息:


public class MainActivity extends Activity implements OnClickListener {

    private MyHandler mHandler = null;
    private Button btn1;
    private TextView mText;
    private HanderThread myThread;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        btn1 = (Button) findViewById(R.id.button1);
        mText = (TextView) findViewById(R.id.textview);
        btn1.setOnClickListener(this);
        mHandler = new MyHandler(Looper.getMainLooper());
    }

    @Override
    public void onClick(View v) {
        // TODO Auto-generated method stub
        switch(v.getId()){
        case R.id.button1:
            myThread = new HanderThread();
            myThread.start();
        }
    }

    class MyHandler extends Handler{
        public MyHandler(Looper looper){
            super(looper);
        }

        public void handleMessage(Message msg){
            //此函數處理handler發送的消息。

            switch(msg.what){
            case 4:
                String obj = msg.getData().getString("senddata");
                mText.setText("receive "+obj);
                break;
            default:
                break;
            }
        }
    }

    class HanderThread extends Thread{
        HanderThread (){
        }

        public void run(){

            // 在這裏你可以做一些費時的操作,本例只是在這裏發送了一個
            //消息給主線程告訴它消息來自子線程,並改變TextView中的文字。

            String msg = "from child thread";
            Bundle mBundle = new Bundle();
            Message Msg = mHandler.obtainMessage();
            mBundle.putString("senddata",msg);
            Msg.what = 4;
            Msg.setData(mBundle);

            //要記住這裏發送這個message的是mHandler,這個handler是
            //屬於主線程的handler所以主線程來處理這個消息。並且有主線程
            //來做出相應的改變。
            mHandler.sendMessage(Msg);

        }
    }

    
public class MainActivity extends Activity {

    private Handler mMainHandler = null;
    private TextView info = null;
    private Button msgBtn = null;
    ChildThread child1 = null;

    class ChildThread extends Thread {
        private Handler childHander = null;
        private String CHILD_TAG = "ChildThread";

        public void run() {
            this.setName("ChildThread");

            // 初始化消息循環隊列,需要在Handler創建之前
            //必須用這個函數和loop(),否則報錯。
            Looper.prepare();

            childHander = new Handler() {
                @Override
                public void handleMessage(Message msg) {

                    // 在子線程中可以做一些耗時的工作
                    String sMsg = "";

                    Message toMain = new Message();

                    // mMainHandler.obtainMessage();
                    toMain.obj = "This message from  "
                            + this.getLooper().getThread().getName()
                            + " the main thread had sent " + (String) msg.obj;

                    // 這個消息是主線程的handler發送的,由主線程處理,這裏
                    //主要是改變主線程TextView的文字。
                    mMainHandler.sendMessage(toMain);
                }
            };
            //使消息開始循環。
            Looper.loop();
        }
    }
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        info = (TextView) findViewById(R.id.info);
        msgBtn = (Button) findViewById(R.id.bt1);

        mMainHandler = new Handler() {

            @Override
            public void handleMessage(Message msg) {

                // 處理收到的消息。
                info.setText((String) msg.obj);
            }

        };
        
        child1 = new ChildThread();
        child1.start();
        
        msgBtn.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {

                if (child1.childHander != null) {

                    // 發送消息給子線程
                    Message childMsg = child1.childHander.obtainMessage();
                    Message msg = new Message();
                    msg.obj = mMainHandler.getLooper().getThread().getName()
                            + " say hello";

                    // 因爲發送這個小時的handler是子線程的所有子線程處理。
                    // 哪個線程處理消息要看是由屬於哪個線程的handler發出的消息。
                    child1.childHander.sendMessage(msg);
                }
            }
        });

    }
}






發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章