[Android] Thread#1 WorkThread to MainThread by Handler

本篇文章為一個 Android WorkerThread的Data透過Handler丟到MainThread中 的範例。

            在一個Android Application中,顯示給User使用的UI介面是工作在主線程上 ,其主線程為MainThread,如果當一個工作阻塞在MainThread中超過5秒(onCreat 10秒),系統即發生ANR事件(Application Not Responding)。

            例如在MainThread中加入一個 Thread.sleep(5000),系統即發生ANR,因此MainThread主要是用來給User使用的UI線程,如果有一些較繁重的工作、重複性高或演算法(例如一個不斷從Internet不斷抓取資料的工作),則需另外開一個Thread(WorkerThread)專門負責該項工作,除了MainThread以外的Thread都稱WorkerThread。

            在一個Application當中,WorkThread無法直接使用TextView、Button等UI控件(progressBar可以),這是因為這些UI控件都是在MainThread當中所生成,因此如果一個WorkerThread想要使用TextView或Button等控件,則需使用Handler,將一個Handler生成在MainThread當中,WorkerThread將資料丟到Handler中後,再將資料顯示在TextView上。以下將示範 點擊Button後,WorkerThread內的Data透過Handler丟到MainThread中的TextView顯示出來:

 

一開始建立所需使用的 button1、textview1、handler1,

private Button button1;//建立button1物件,點擊按鈕時,執行MyThread Function,讓MyThread透過handler1傳送 字串給textview1
private TextView textview1;//建立textview1物件
private Handler handler1;  //建立handler1

   在onCreat中將button1與textview1綁定ID,button1的監聽器綁button1listener() function,

    將handler1綁Myhandler() function。

 protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        button1=(Button)findViewById(R.id.btn1ID);
        textview1=(TextView)findViewById(R.id.tv1ID);
        button1.setOnClickListener(new button1listener());
        handler1=new MyHandler(); //handler1綁MyHandler Function

    }

 建立一個 Button onClickListener的 class,實現 onClickListener,當點擊Button1時,將運行此Function,此Function將建立一個Thread t,其綁到MyThread() function

上,並使用 start()方始使該Thread開始執行。

class button1listener implements View.OnClickListener{  //點擊button1時,建立一個t綁MyThread,並使之開始
        @Override
        public void onClick(View v) {
            Thread t=new MyThread();//建立一個Thread t使用MyThread function
            t.start(); //t開始
        }
    }

 建立一個名稱為 MyThread的WorkerThread,其class是繼承 Thread方法。

在MyThread當中,建立一個信息對象msg獲取handler1.obtainMessage(),得到handler1的消息對象後,

便可對msg丟data,如果是 data是int,使用msg.what儲存資料,如果data是string,則使用msg.obj儲存資料。

最後再透過handler1.sendMessage(msg) 方法,將資料丟到消息對列當中。

  //WorkerThread
    class MyThread extends Thread{  //將字串存到handler1的msg
        @Override
        public void run(){
            try {
                Thread.sleep(1*1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            String s="This is MyThread's string";

            //創建一個消息對象,並使用Handler發送該對象
            Message msg=handler1.obtainMessage(); //獲取handler1的消息對象
            msg.obj= s;//設定消息=s

            handler1.sendMessage(msg);//將消息(msg)放在消息對列中
            //1.Looper將會從消息對列中取出msg
            //2.Looper將會找到與消息對象對應的Handler對象 (此處 msg與handler1對應)
            //3.Looper將會調用handler1對象的handlerMessage(Message msg)方法,用於處理消息對象
        }
    }

 建立一個MyHandler,其class繼承Handler方法。 其MyHandler是建立在MainThread當中,因此會不斷地循環偵測Message

其handleMessage內,將消息對列中的msg抓出來並儲存到 obj中,再將obj資料顯示在textview1。

 class MyHandler extends Handler{
        @Override
        public void handleMessage(Message msg){
            Object obj=msg.obj;

            textview1.setText(obj + "");
            System.out.println(obj+"");
        }
    }

以上為WorkerThread向MainThread丟資料的方法,下一篇則是相反,由MainThread向WorkerThread丟資料。