1. 程式人生 > >多執行緒通訊之Handler實現

多執行緒通訊之Handler實現

在Android系統中,多執行緒之間傳遞訊息我們可以用Handler來實現

UI執行緒向子執行緒傳送訊息,子執行緒接收到訊息後處理

public class MainToWorkThreadActivity extends Activity {
    private Handler handler;
    private Button button1;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main_to_work_thread);

        button1 = (Button) findViewById(R.id.button1);
        button1.setOnClickListener(new
OnClickListener() { @Override public void onClick(View v) { // 在主執行緒傳送訊息 System.out.println("onClick: " + Thread.currentThread().getName()); Message msg = handler.obtainMessage(); msg.what = 100
; handler.sendMessage(msg); } }); new Thread() { @Override // 線上程中處理主執行緒傳送的訊息物件 // 為什麼工作執行緒中需要Looper物件,而主執行緒不需要?? public void run() { // 準備Looper物件 Looper.prepare(); // 在WorkThread當中生成一個Handler物件
handler = new Handler() { @Override public void handleMessage(Message msg) { super.handleMessage(msg); System.out.println("handleMessage: " + Thread.currentThread().getName()); } }; // 呼叫Looper的loop()方法之後,Looper物件將不斷的從訊息佇列中取出訊息物件, // 然後呼叫handlerMessage()方法處理該訊息物件 // 如果訊息佇列中沒有物件,則該執行緒阻塞 Looper.loop(); } }.start(); } }

子執行緒向UI執行緒傳送訊息,UI執行緒接收訊息後處理

public class WorkToMainThreadActivity extends Activity {
    private Button button1, button2, button3;
    private ProgressBar progressBar;
    private Handler handler;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_maintoworkthread);

        button1 = (Button) findViewById(R.id.button1);
        button2 = (Button) findViewById(R.id.button2);
        button3 = (Button) findViewById(R.id.button3);
        progressBar = (ProgressBar) findViewById(R.id.progressBar);
        progressBar.setMax(100);

        /*
         * 在java中可有兩種方式實現多執行緒,一種是繼承Thread類,一種是實現Runnable介面;
         * Thread類是在java.lang包中定義的。一個類只要繼承了Thread類同時覆寫了本類中的run()
         * 方法就可以實現多執行緒操作了,但是一個類只能繼承一個父類,這是此方法的侷限。 兩種實現方式的區別和聯絡:
         *
         * 在程式開發中只要是多執行緒肯定永遠以實現Runnable介面為主,因為實現Runnable介面相比繼承Thread類有如下好處:
         * 1.避免點繼承的侷限,一個類可以繼承多個介面。 2.適合於資源的共享
         */
        button1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // 繼承Thread方法實現多執行緒
                new Thread() {
                    @Override
                    public void run() {
                        System.out.println("button1.onClick.run: " + Thread.currentThread().getId()+ Thread.currentThread().getName());
                        try {
                            int i = 5;
                            while (i <= 100) {
                                sleep(500);
                                Message msg = handler.obtainMessage();
                                msg.arg1 = i;
                                handler.sendMessage(msg);
                                // 上面一行程式碼將訊息物件放置到訊息隊列當中
                                // 1.Looper將會從訊息隊列當中將訊息物件取出
                                // 2.Looper將會找到與訊息物件對應的Handler物件
                                // 3.Looper將會呼叫handler物件的handleMessage(Message msg)方法,用於處理訊息物件
                                i += 5;
                            }
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        super.run();
                    }
                }.start();
            }
        });
        button2.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                /*
                 * 在實際開發中一個多執行緒的操作很少使用Thread類,而是通過Runnable介面完成。
                 * 但是在使用Runnable定義的子類中沒有start()方法,只有Thread類中才有。
                 * 此時觀察Thread類,有一個構造方法:public Thread(Runnable targer)此構造方法接受Runnable的子類例項,
                 * 也就是說可以通過Thread類來啟動Runnable實現的多執行緒。(start()可以協調系統的資源)
                 */
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        System.out.println("button2.onClick.run: " + Thread.currentThread().getId()+ Thread.currentThread().getName());
                        try {
                            int i = 10;
                            while (i <= 100) {
                                Thread.sleep(1000);
                                Message msg = handler.obtainMessage();
                                msg.arg1 = i;
                                handler.sendMessage(msg);
                                i += 10;
                            }
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }).start();
            }
        });

        button3.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                /*
                 * Runnable物件和主使用者介面執行緒的ID是相同。在這個例子中,我們直接利用handler物件post了一個runnable物件
                 * ,相當於直接呼叫了Runnable物件的run函式,也就說沒有經過start函式呼叫run(),那麼就不會建立一個新執行緒,
                 * 而是在原有執行緒內部直接呼叫 run()方法,因此輸出的執行緒Id是相同的。
                 */
                handler.post(new Runnable() {
                    @Override
                    public void run() {
                        System.out.println("button3.onClick.run: " + Thread.currentThread().getId()+ Thread.currentThread().getName());
                        try {
                            int i = 1;
                            while (i <= 100) {
                                Thread.sleep(100);
                                Message msg = handler.obtainMessage();
                                msg.arg1 = i;
                                handler.sendMessage(msg);
                                i += 1;
                            }
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                });
            }
        });

        handler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                // 在主執行緒處理訊息,工作執行緒傳送訊息,以方便執行緒間通訊
                // 這樣可以解決工作執行緒不能操作UI的問題
                System.out.println("handleMessage: " + Thread.currentThread().getId() + Thread.currentThread().getName());
                progressBar.setProgress(msg.arg1);
                super.handleMessage(msg);
            }
        };
    }
}