(1)Handler的定义
当应用程序启动时,Android首先会开启一个主线程 (也就是UI线程) ,主线程管理界面中的UI控件。如果此时需要一个耗时的操作,例如联网读取数据,或者读取本地较大的一个文件的时候,你不能把这些操作放在主线程中。如果你放在主线程中的话,UI界面会出现假死现象,如果5秒钟还没有完成的话,会收到Android系统的一个错误提示 "强制关闭"。
这个时候我们需要把这些耗时的操作,放在其它线程中。 这个时候Handler就出现了来解决这个复杂的问题,由于Handler运行在主线程中(UI线程中),它与子线程可以通过Message对象来传递数据,这些消息会被子线程发往主线程队列中,配合主线程进行更新UI。
(2)Handler一些特点
每个Handler实例,都会绑定到创建它的线程中(一般是主线程)。它有两个作用:a, 发送消息;b,安排Runnable 。
安排Runnable的一些方法:
post(Runnable)
postAtTime(Runnable,long)
postDelayed(Runnable, long)
发送消息的一些方法:
sendEmptyMessage(what)
sendMessage(Message)
sendMessageAtTime(Message,long)
sendMessageDelayed(Message,long)
以上post类方法允许你排列一个Runnable对象到主线程队列中,sendMessage类方法允许你发送一个带数据的Message对象到队列中,等待更新。
(3)消息机制的几个常见名词概念
A,Handler:消息的封装者和处理者,handler负责将需要传递的信息封装成Message,将消息传递给Looper,继而由Looper将Message放入MessageQueue中。当Looper对象看到MessageQueue中含有Message,就将其广播出去。该handler对象收到该消息后,调用相应的handler对象的handleMessage()方法对其进行处理。
B,Message:消息对象,Message Queue中的存放的对象。一个Message Queue中包含多个Message。Message实例对象的取得,通常使用Message类里的静态方法obtain(),该方法有多个重载版本可供选择;调用removeMessages()时,将Message从Message Queue中删除。
C,MessageQueue:就是一个消息队列,存放消息的地方。每一个线程最多只可以拥有一个MessageQueue数据结构。创建一个线程的时候,并不会自动创建其MessageQueue。通常使用一个Looper对象对该线程的MessageQueue进行管理。主线程创建时,会创建一个默认的Looper对象,而Looper对象的创建,将自动创建一个Message Queue。其他非主线程,不会自动创建Looper,要需要的时候,通过调用prepare函数来实现,和Looper.loop()。
D,Looper:是MessageQueue的管理者。每一个MessageQueue都不能脱离Looper而存在,Looper对象的创建是通过prepare函数来实现的。同时每一个Looper对象和一个线程关联。通过调用Looper.myLooper()可以获得当前线程的Looper对象,创建一个Looper对象时,会同时创建一个MessageQueue对象。除了主线程有默认的Looper,其他线程默认是没有MessageQueue对象的,所以,不能接受Message。如需要接受,自己定义一个Looper对象(通过prepare函数),这样该线程就有了自己的Looper对象和MessageQueue数据结构了。Looper从MessageQueue中取出Message然后,交由Handler的handleMessage进行处理。
(4)Handler实例
以下为一个实例,它实现的功能为通过线程修改Button的内容,即子线程发消息给主线程
public class MainActivity extends Activity {
Button button;
MyHandler myHandler;
public static final String Tag = "handler";
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button = (Button) findViewById(R.id.button1);
myHandler = new MyHandler();
myHandler.postDelayed(myRunnable, 1000);
}
class MyHandler extends Handler {
public MyHandler() {
}
public MyHandler(Looper L) {
super(L);
}
// <strong>子类必须重写此方法,接受数据 </strong>
@Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
Log.d("MyHandler", "handleMessage......");
super.handleMessage(msg);
// 此处可以更新UI
Bundle b = msg.getData();
String color = b.getString("color");
MainActivity.this.button.append(color);
}
}
private Runnable myRunnable= new Runnable() {
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Message msg = new Message();
Bundle b = new Bundle();// 存放数据
b.putString("color", "我的");
msg.setData(b);
myHandler.sendMessage(msg); // 向Handler发送消息,更新UI
}
};
}
除上述用法之外,主线程给主线程自己发消息、主线程给子线程发消息、子线程给子线程自己发消息,样例都可以参见http://blog.csdn.net/aaa2832/article/details/7773220#comments,
(5)为什么不能再子线程中更新UI,仅能发出消息
如果在子线程中直接更新UI,通常会抛出下面的异常:
11-07 13:33:04.393: ERROR/JavaBinder(1029):android.view.ViewRoot$CalledFromWrongThreadException:Only the original thread that created a view hierarchy can touch its views.意思是,无法在子线程中更新UI。
(6)Handler用定时器执行重复刷UI的操作
需要引入import java.util.Timer; 和 import java.util.TimerTask;首先Timer用来定时执行某个TimerTask, TimerTask仅仅用Handler来发出刷界面的消息,而不是去刷界面,刷界面的操作由handleMessage来完成就行了。
public class TestTimer extends Activity {
Timer timer = new Timer();
Handler handler = new Handler(){
public void handleMessage(Message msg) {
switch (msg.what) {
case 1:
setTitle("hear me?");
break;
}
super.handleMessage(msg);
}
};
TimerTask task = new TimerTask(){
public void run() {
Message message = new Message();
message.what = 1;
handler.sendMessage(message);
}
};
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
timer.schedule(task, 10000);
}
}
(7)Handler用于设置某个时间点执行某个操作。 Runnable + Handler.postDelayed(runnable,time),DEMO如下:
private Handler handler = new Handler();
private Runnable myRunnable= new Runnable() {
public void run() {
if (run) {
handler.postDelayed(this, 1000);
count++;
}
tvCounter.setText("Count: " + count);
}
};
postDelayed的结果指向自己,也可以完成重复的操作
(8)如何在service中调用activity中的handler
在service中定义一个handler,然后定义一个void sethandler(Handler handler )把activity的handler传过来,在service中sendmessage,activity中就可以接收了
参考原文:http://www.cnblogs.com/devinzhang/archive/2011/12/30/2306980.html
参考原文:http://www.cnblogs.com/dawei/archive/2011/04/09/2010259.html
参考原文:http://bbs.csdn.net/topics/370191134
参考原文:http://blog.csdn.net/chenqiumiao/article/details/7652745