Android的Handler機制的一些理解

Handler是什麼

在Android中表示一種消息處理機制或者叫消息處理方法,用來循環處理應用程序主線程各類消息,好比UI的更新,按鍵、觸摸消息事件等。android

 

爲何Android要用Handler機制

Android應用程序啓動時,系統會建立一個主線程,負責與UI組件(widget、view)進行交互,好比控制UI界面界面顯示、更新等;分發事件給UI界面處理,好比按鍵事件、觸摸事件、屏幕繪圖事件等,所以,Android主線程也稱爲UI線程。
由此可知,UI線程只能處理一些簡單的、短暫的操做,若是要執行繁重的任務或者耗時很長的操做,好比訪問網絡、數據庫、下載等,這種單線程模型會致使線程運行性能大大下降,甚至阻塞UI線程,若是被阻塞超過5秒,系統會提示應用程序無相應對話框,縮寫爲ANR,致使退出整個應用程序或者短暫殺死應用程序。數據庫

除此以外,單線程模型的UI主線程也是不安全的,會形成不可肯定的結果。線程不安全簡單理解爲:多線程訪問資源時,有可能出現多個線程前後更改數據形成數據不一致。好比,A工做線程(也稱爲子線程)訪問某個公共UI資源,B工做線程在某個時候也訪問了該公共資源,當B線程正訪問時,公共資源的屬性已經被A改變了,這樣B獲得的結果不是所須要的的,形成了數據不一致的混亂狀況。
線程安全簡單理解爲:當一個線程訪問功能資源時,對該資源進程了保護,好比加了鎖機制,當前線程在沒有訪問結束釋放鎖以前,其餘線程只能等待直到釋放鎖才能訪問,這樣的線程就是安全的。安全

基於以上緣由,Android的單線程模型必須遵照兩個規則:
1.  不要阻塞UI線程;
2.  不要在UI線程以外訪問UI組件,即不能在子線程訪問UI組件,只能在UI線程訪問。網絡

所以,Android系統將大部分耗時、繁重任務交給子線程完成,不會在主線程中完成,解決了第一個難題;同時,Android只容許主線程更新UI界面,子線程處理後的結果沒法和主線程交互,即沒法直接訪問主線程,這就要用到Handler機制來解決此問題。基於Handler機制,在子線程先得到Handler對象,該對象將數據發送到主線程消息隊列,主線程經過Loop循環獲取消息交給Handler處理。多線程

 

案例用法

下面兩個案例都實現一個定時器,每隔一秒顯示數字0-9app

案例1:sendMenssage方法更新UI界面ide

 1 package com.example.testhandler;
 2  
 3 import android.app.Activity;
 4 import android.os.Bundle;
 5 import android.os.Handler;
 6 import android.os.Message;
 7 import android.view.View;
 8 import android.view.View.OnClickListener;
 9 import android.widget.Button;
10 import android.widget.TextView;
11  
12 public class TestHandlerActivity extends Activity {
13  
14     protected static final String TAG = "TestHandlerActivity";
15     private Button sendButton;
16     private TextView displayText;
17  
18     Handler mHandler = new Handler() {
19  
20         @Override
21         public void handleMessage(Message msg) {
22             // TODO Auto-generated method stub
23             if (msg.what == 99) {
24                 int i = msg.getData().getInt("displayKey");
25                 displayText.setText(i + "");
26             }
27             super.handleMessage(msg);
28         }
29  
30     };
31     private Button exitButton;
32  
33     @Override
34     protected void onCreate(Bundle savedInstanceState) {
35         super.onCreate(savedInstanceState);
36         setContentView(R.layout.activity_main);
37         initViews();
38     }
39  
40     private void initViews() {
41  
42         displayText = (TextView) findViewById(R.id.display_text);
43         sendButton = (Button) findViewById(R.id.send_button);
44         sendButton.setOnClickListener(buttonOnClickListener);
45         exitButton = (Button) findViewById(R.id.exit_button);
46         exitButton.setOnClickListener(buttonOnClickListener);
47     }
48  
49     OnClickListener buttonOnClickListener = new OnClickListener() {
50  
51         @Override
52         public void onClick(View v) {
53             // TODO Auto-generated method stub
54             if (v.getId() == R.id.send_button) {
55                 new Thread(new WorkRunnable()).start();
56             } else if (v.getId() == R.id.exit_button) {
57                 finish();
58             }
59         }
60  
61     };
62  
63     class WorkRunnable implements Runnable {
64         @Override
65         public void run() {
66             // TODO Auto-generated method stub
67             int i = 0;
68             while (i < 10) {
69                 Message msg = mHandler.obtainMessage(99);
70                 Bundle bundle = new Bundle();
71                 bundle.putInt("displayKey", i);
72                 msg.setData(bundle);
73                 mHandler.sendMessage(msg);
74                 try {
75                     Thread.sleep(1000);
76                 } catch (InterruptedException e) {
77                     // TODO Auto-generated catch block
78                     e.printStackTrace();
79                 }
80                 i++;
81             }
82         }
83     }
84  
85     @Override
86     protected void onDestroy() {
87         // TODO Auto-generated method stub
88         if (mHandler != null) {
89             if (mHandler.hasMessages(99)) {
90                 mHandler.removeMessages(99);
91             }
92             mHandler = null;
93         }
94         super.onDestroy();
95     }
96 }

WorkRunnable的run方法中進行了耗時操做,要把結果反饋給UI,須要Handler發送消息給UI線程,在Handler的handleMessage對消息進行處理oop

 

案例2: postDelayed更新UIpost

 1 package com.example.postdelaydemo;
 2  
 3 import android.app.Activity;
 4 import android.os.Bundle;
 5 import android.os.Handler;
 6 import android.util.Log;
 7 import android.view.View;
 8 import android.view.View.OnClickListener;
 9 import android.widget.Button;
10 import android.widget.TextView;
11  
12 public class PostDelayActivity extends Activity {
13     protected static final String TAG = "PostDelayActivity";
14     private Button sendButton;
15     private TextView displayText;
16     private Button exitButton;
17     Handler mHandler = new Handler();
18  
19     @Override
20     protected void onCreate(Bundle savedInstanceState) {
21         super.onCreate(savedInstanceState);
22         setContentView(R.layout.activity_main);
23         initViews();
24     }
25  
26     private void initViews() {
27         displayText = (TextView) findViewById(R.id.display_text);
28         sendButton = (Button) findViewById(R.id.send_button);
29         sendButton.setOnClickListener(buttonOnClickListener);
30         exitButton = (Button) findViewById(R.id.exit_button);
31         exitButton.setOnClickListener(buttonOnClickListener);
32     }
33  
34     OnClickListener buttonOnClickListener = new OnClickListener() {
35         @Override
36         public void onClick(View v) {
37             // TODO Auto-generated method stub
38             if (v.getId() == R.id.send_button) {
39                 mHandler.postDelayed(new PostDelayRunnable(), 1000);
40             } else if (v.getId() == R.id.exit_button) {
41                 finish();
42             }
43         }
44     };
45  
46     class PostDelayRunnable implements Runnable {
47         int i = 0;
48  
49         @Override
50         public void run() {
51             // TODO Auto-generated method stub
52             if (i >= 10) {
53                 mHandler.removeCallbacks(this);
54             } else {
55                 displayText.setText(getResources().getString(
56                         R.string.display_label)
57                         + i);
58                 mHandler.postDelayed(this, 1000);
59             }
60             i++;
61         }
62     }
63  
64     @Override
65     protected void onDestroy() {
66         // TODO Auto-generated method stub
67         if (mHandler != null) {
68             mHandler = null;
69         }
70         super.onDestroy();
71     }
72 }

postDelayed方法把runnable對象做爲消息放到隊列中等待執行,run方法中就是具體執行過程。性能

 

msg.target是Handler的一個對象引用,handler對象發送消息暫存到消息隊列,Looper取出消息分發給相應的handler處理。

 

Handler.post(new Runnable())和sendmessage(msg)區別

(1)  都是把消息放到消息隊列等待執行,前者放的是一個runnable對象,後者是一個message對象;
(2)  前者最終仍是會轉化成sendMessage,只不過最終的處理方式不同,前者會執行runnable的run方法;後者能夠被安排到線程中執行。

(3)  二者本質沒有區別,均可以更新UI,區別在因而否易於維護等。

 

HandlerThread是什麼

HandlerThread繼承了Thread,是一個包含有looper的線程類。正常狀況下,除了主線程,工做線程是沒有looper的,可是爲了像主線程那樣也能循環處理消息,Android也自定義一個包含looper的工做線程——HandlerThread類。

 

啊啊啊啊啊啊啊啊西吧太菜了,源碼看不懂

相關文章
相關標籤/搜索