Android的Handler机制的一些理解

Handler是什么

在Android中表示一种消息处理机制或者叫消息处理方法,用来循环处理应用程序主线程各种消息,比如UI的更新,按键、触摸消息事件等。

为什么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-9

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

 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对消息进行处理

案例2: postDelayed更新UI

 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类。

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

原文地址:https://www.cnblogs.com/tero/p/5304118.html