简单地理解,Handler是当前线程的消息队列中的一个子队列,而Runable是可以被安排到Handler去运行的接口。
首先在Activity中创建一个继承自Handler的匿名内部类以及这个类的一个对象
Private MainHandler mMainHandler = new MainHandler();
private class MainHandler extends Handler {
public void handleMessage(android.os.Message msg) {
switch (msg.what) {
case MSG_MAIN_HANDLER_TEST:
Log.d(TAG, "handleMessage-->thread id = " +
Thread.currentThread().getId());
break;
}
}
};
这样在Activity的其他地方就可以通过mMainHandler对象发送消息给Handler处理了
Message msg = mMainHandler.obtainMessage(MSG_MAIN_HANDLER_TEST);
mMainHandler.sendMessage(msg);
使用Handler发送以及处理消息外,handler还有一个作用就是处理传递给它的action对象,具体使用步骤示例:
1、在主线程中定义Handler对象
2、构造一个runnable对象,为该对象实现runnable方法。
3、在子线程中使用Handler对象post(runnable)对象.
handler.post这个函数的作用是把Runnable里面的run方法的这段代码发送到消息队列中,等待运行。
如果handler是以UI线程消息队列为参数构造的,那么是把run里面的代码发送到UI线程中,等待UI线程运行这段代码。如果handler是以子线程线程消息队列为参数构造的,那么是把run里面的代码发送到子线程中,等待子线程运行这段代码。
Runnable本身并不是一个线程,只是接口,但是这个接口可以在别的线程中运行
public class TestActivity extends Activity implements OnClickListener {
private Button mBtnTest=null;
private Handler myHandler=null;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mBtnTest=(Button)findViewById(R.id.btn_test);
mBtnTest.setOnClickListener(this);
myHandler=new Handler();
}
@Override
public void onClick(View v) {
//注意:此处UI线程被阻塞,因为myHandler是在UI线程中创建的
myHandler.post(new Runnable() {
public void run() {
long i=0;
while(true){
i++;
}
}
});
}
}
这里我们看代码 mHandler.post(new Runnable(){ 好像是new 了一个 interface,其实是new的一个实现Runnable的匿名内部类(Inner Anonymous Class),这是很简练的写法。
上面的代码可以看成是: new anonymousClass() implement interface{ [改写interface method]}
Runnable是一个接口,不是一个线程,一般线程会实现Runnable。所以如果我们使用匿名内部类是运行在UI主线程的,如果我们使用实现这个Runnable接口的线程类,则是运行在对应线程的。
而Android应用程序是消息驱动的。Android通过Looper、Handler来实现消息循环机制,Android消息循环是针对线程的(每个线程都可以有自己的消息队列和消息循环)。
Message:消息,其中包含了消息ID,消息处理对象以及处理的数据等,由MessageQueue统一列队,终由Handler处理。
Handler:处理者,负责Message的发送及处理。使用Handler时,需要实现handleMessage(Message msg)方法来对特定的Message进行处理。
MessageQueue:消息队列,用来存放Handler发送过来的消息,并按照FIFO规则执行。当然,存放Message并非实际意义的保存,而是将Message以链表的方式串联起来的,等待Looper的抽取。
Looper:消息泵,不断地从MessageQueue中抽取Message执行。因此,一个MessageQueue需要一个Looper。
Thread:线程,负责调度整个消息循环,即消息循环的执行场所。
Handler,Looper和MessageQueue就是简单的三角关系。Looper和MessageQueue一一对应,创建一个 Looper的同时,会创建一个MessageQueue。而Handler与它们的关系,只是简单的聚集关系,即Handler里会引用当前线程里的特定Looper和MessageQueue。
这样说来,多个Handler都可以共享同一Looper和MessageQueue了。当然,这些Handler也就运行在同一个线程里。
如何实现消息的发送与处理
接下来,我们简单地看一下消息的循环过程:
A消息的生成
Message msg = mHandler.obtainMessage();
msg.what = what;
msg.sendToTarget();
B消息的发送
MessageQueue queue = mQueue;
if (queue != null) {
msg.target = this;
sent = queue.enqueueMessage(msg, uptimeMillis);
}
在Handler.java 的sendMessageAtTime(Message msg, long uptimeMillis)方法中,我们看到,它找到它所引用的MessageQueue,然后将Message的target设定成自己(目的是为了在处理消息环节,Message能找到正确的Handler),再将这个Message纳入到消息队列中。
C消息的抽取
Looper me = myLooper();
MessageQueue queue = me.mQueue;
while (true) {
Message msg = queue.next(); // might block
if (msg != null) {
if (msg.target == null) {
// No target is a magic identifier for the quit message.
return;
}
msg.target.dispatchMessage(msg);
msg.recycle();
}
}
在Looper.java 的loop()函数里,我们看到,这里有一个死循环,不断地从MessageQueue中获取下一个(next方法)Message,然后通过Message中携带的target信息,交由正确的Handler处理(dispatchMessage方法)。
D消息的处理
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
在Handler.java的dispatchMessage(Message msg)方法里,其中的一个分支就是调用handleMessage方法来处理这条Message,而这也正是我们在职责处描述使用Handler时需要实现handleMessage(Message msg)的原因。
一个Message经由Handler的发送,MessageQueue的入队,Looper的抽取,又再一次地回到Handler的怀抱。而绕的这一圈,也正好帮助我们将同步操作变成了异步操作。