線程間通信----Handler

   Android中規定:

   (1)不能阻礙UI主線程,達到5秒以上會自動報錯(ANR應用程序無法響應)

   (2)不要讓UI主線程之外的線程去更新主UI,否則繪世界報錯

   例:

public class MainActivity extends Activity {
    private TextView tv;
                                                                                                      
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tv = (TextView) findViewById(R.id.textView1);
        findViewById(R.id.strat).setOnClickListener(new OnClickListener() {
                                                                                                              
            @Override
            public void onClick(View arg0) {
                thread.start();//單擊按鈕啓動一個子線程
            }
        });
    }
                                                                                                     
    Thread thread = new Thread(){
        public void run() {
            tv.setText("hello");//在子線程中更新UI
        };
    };
                                                                                                     
                                                                                                      
}

   結果:

   那麼如何解決上面出現的問題呢?可以用我們的Handler

   一:Handler

   Handler對象的使用和線程相關,也就是說,他會綁定一個線程,讓這個耗時的操作在新建的線程上完成,而達到不阻礙主UI線程的操作,從而達到線程之間的通信。

   二:用途

   (1)發送消息

   可以使用post(runnable對象)、postDelay(runnable對象,int時間間隔)等方法發送Runnable對象,從而與主UI線程進行通信。

   可以使用sendMessage(Message對象)、sendMessage(Message對象,int時間間隔)等方法發送Message對象,從而與主UI線程進行通信。

   (2)接收消息

   可以使用handleMessage(Message對象)方法處理接收得到的Message

   三:常用的Handler方法

   (1)post(runnable對象):啓動線程,在線程中處理耗時操作

   (2)postDelay(runnable對象,int時間間隔): 每隔多長時間執行一次線程

   (3)sendMessage(Message對象):發送消息給主線程

   (4)handleMessage(Message對象):接收消息,並更新UI

   四:發送Runnable對象,從而與主UI線程進行通信

功能:在新建的線程中,完成計數操作,並更新主UI上的控件。

   (1)創建Handler對象,並實例化

// 創建Handler對象
    private Handler handler = new Handler();

   (2)創建線程,完成計數操作,並更新主UI

// 創建線程
    Runnable runnable = new Runnable() {
        int count = 0;
        @Override
        public void run() {
            count++;
            tv.setText(count + "");// 更新UI
            // System.out.println("我是子線程");
            handler.postDelayed(runnable, 1000);// 每隔一秒執行一次線程
        }
    };

   (3)主界面添加按鈕。啓動按鈕: 通過handler啓動子線程;停止按鈕:移除線程對象

private Button startBtn, stopBtn;// 聲明按鈕
    private TextView tv;// 聲明文本框
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        // 查找資源
        startBtn = (Button) findViewById(R.id.start);
        stopBtn = (Button) findViewById(R.id.stop);
        tv = (TextView) findViewById(R.id.textView1);
        // 爲按鈕添加監聽
        startBtn.setOnClickListener(this);
        stopBtn.setOnClickListener(this);
    }
    @Override
    public void onClick(View v) {
        switch (v.getId()) {
        case R.id.start:
            handler.post(runnable);// 通過Handler啓動線程
            break;
        case R.id.stop:
            // 移除子線程
            handler.removeCallbacks(runnable);
            break;
        }
    }

   ◆結果:單擊start按鈕,主UI開始更新,單擊stop時候停止更新。

   五:使用sendMessage(Message對象)和handleMessage(Message對象)實現Message對象的接受與發送

    功能:這裏利用的sendMessage發送消息,用handleMessage方法去更新UI。讓ProgressBar自動更新,在TextView中實時顯示進度條中的值。

具體實現:

   (1)創建handler對象和子線程,用Message封裝消息,通過handler的sendMessage方法發送消息。

    Runnable runnable = new Runnable() {
        @Override
        public void run() {
            count += 10;
//          Message message = new Message();// 創建消息的承載對象這樣會創建很多個Message對象
            //創建Message對象承載信息
            Message message = handler.obtainMessage();//這樣創建的Message只會有一個
            //Message存儲消息
            message.arg1 = count;// 承載數據
            handler.sendMessage(message);// 發送消息
            handler.postDelayed(runnable, 1000);// 每隔一秒執行一次線程
        }
    };

(2)實例化handler對象,實現其中的handleMessage方法,接收消息,更新UI

private Handler handler = new Handler() {
        public void handleMessage(Message msg) {// 接受消息
            pgbar.setProgress(msg.arg1);// 更新主界面的UI
            tv.setText(msg.arg1+"");
            if (msg.arg1 ==100) {// 做判斷
                count=0;
                tv.setText("到頭了。。");
                handler.removeCallbacks(runnable);// 移除UI
            }
        };
    };

   (3)在主界面中給按鈕添加監聽,通過Handler對象以啓動和移除線程

private ProgressBar pgbar;
    private TextView tv;
    private int count = 0;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        pgbar = (ProgressBar) findViewById(R.id.progressBar1);
        tv = (TextView) findViewById(R.id.textView1);
                                                                                                                                                                                                                           
        findViewById(R.id.start).setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                handler.post(runnable);// 啓動線程
            }
        });
        findViewById(R.id.stop).setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                handler.removeCallbacks(runnable);// 移除線程
            }
        });
    }

結果:單擊開始按鈕,滾動條與TextView同時更新,且同步,任意位置單擊按鈕時,均可以停止。

   六:運用Handler實現屏幕的自動滾屏

   (1)在主界面上添加一個ScrollView,在其中的的LinearLayout下添加一個TextView,裏面添加足夠多的文字

   (2)在主界面上實例化Handler對象,在其中的handleMessage方法中實現滾屏效果,具體如下

handler = new Handler() {//實例化Handler對象
            public void handleMessage(android.os.Message msg) {
                if (msg.what == 1) {//判斷消息的標示
                    int startPosition = sv.getScrollY();//得到當前的Y值
                    if (startPosition == 0 || startPosition != lastPosition) {//判斷條件,看看是不是到達底部或者是不是開始位置
                        lastPosition = sv.getScrollY();//若是,則獲得Y值
                        sv.scrollBy(0, 2);//X座標不變,Y值每次加2 實現豎屏滾動
                        handler.sendEmptyMessageDelayed(1, 100);//發送消息
                    }
                }
            };
        };
        handler.sendEmptyMessageDelayed(1, 100);//發送消息標識爲1 的消息,每個0.1秒發送一個消息

   (3)結果:出現自動滾屏效果,可自行查看。

   還有一種比Handler輕量級的線程通信處理方式-----AsynTask,咱們明日再續。



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