在Android中表示一种消息处理机制或者叫消息处理方法,用来循环处理应用程序主线程各种消息,比如UI的更新,按键、触摸消息事件等。
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处理。
(1) 都是把消息放到消息队列等待执行,前者放的是一个runnable对象,后者是一个message对象;
(2) 前者最终还是会转化成sendMessage,只不过最终的处理方式不一样,前者会执行runnable的run方法;后者可以被安排到线程中执行。
(3) 两者本质没有区别,都可以更新UI,区别在于是否易于维护等。
HandlerThread继承了Thread,是一个包含有looper的线程类。正常情况下,除了主线程,工作线程是没有looper的,但是为了像主线程那样也能循环处理消息,Android也自定义一个包含looper的工作线程——HandlerThread类。
啊啊啊啊啊啊啊啊西吧太菜了,源码看不懂
原文:http://www.cnblogs.com/tero/p/5304118.html