概述
一、线程Thread与AsyncTask、Handler关系
我们创建的Service、Activity以及Broadcast均是一个主线程处理,这里我们可以理解为UI线程。google为了保障用户体验,规定主线程(UI界面)5s没响应就报错—ANR异常(Applicationnot Responding),所以较为耗时的操作一般需要开启子线程完成,即Thread。
对于从事过J2ME开发的程序员来说Thread比较简单,直接匿名创建重写run方法,调用start方法执行即可,或者从Runnable接口继承,但对于Android平台来说UI控件都没有设计成为线程安全类型,所以需要引入一些同步的机制来使其刷新,因为Google做了限定,只有主线程才可以与UI界面进行交互只有主(进度条除外),即刷新UI元素,所以仅仅使用Thread无法将运行结果刷新到UI界面,所以android搞了一个消息机制Handler,利用Handler建立子线程与主线程UI之间的交互联系。
Handler工作模式大致是:
子线程:在一个线程的run方法中,将运行结果存放到Message,然后调用handler对象的 postMessage或sendMessage方法来实现将Message发送到主线程即UI线程,每一个消息都有一个标示Message.what以方便辨识。
UI线程(主线程):主线程通过Handle处理发送到主线程的Message,即重写Handle的HandleMessage函数,在其中刷新UI。
所以,但仅通过Thread+Handler实现子线程与主线程之间的交互还不够,如何确保消息队列源源不断的被取出?这里需要 Looper循环去取消息,其实Android中每一个Thread都跟个Looper,Looper可以帮助Thread维护一个消息队列。因此,准确说,应该是Thread+Handler+Looper,三者结合共同实现消息传递机制。
另外,Android为了方便开发,将三者的实现过程整合到AsyncTask中,故AsyncTask可以简单的开启线程并与主线程进行交互。
二、Handler消息(Message)传递机制
Handler具有唯一性,即一旦创建Handler,Handler将与该线程进行绑定,管理该线程的消息队列,因此,Handler主要有两个功能,以主线程中的Handler为例:
1)传递其他线程中的消息进队列。利用handler.sendMessage()或handler. postMessage()管理消息在队列中的位置
2)队列中的消息与UI交互。利用Handler.HandleMessage()函数与UI交互。
一个完整的消息传递机制如下图,有三个要素,分别是Message消息,MessageQueue消息队列,Looper循环泵。 Handler负责将子线程的Message进入队列排序确定位置,并将Looper循环泵出来的队首消息与主线程交互。具体过程见下面的源码过程分析。
三、Handler消息传递机制过程源码分析(以Activity主线程为例)
1)创建 new Handler()
Handler()的构造函数如下:
public Handler(Callback callback, boolean async) {
mLooper = Looper.myLooper();
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
所以,创建Handler,即自动绑定了一个Looper以及一个消息队列mQueue,以及一个回调接口Callback(如下),handleMessage()是一个空函数,承担与UI交互功能,所以需要在主线程中重写。
public interface Callback {
public boolean handleMessage(Message msg);
}
2)获取Message(Message是一个final类),Android推荐用Message.obtain()或者Handler.obtainMessage()获取Message
public final Message obtainMessage()
{
return Message.obtain(this);
}
obtain(this),this即为Handler,Message中对应的obtain()函数如下:
public static Message obtain(Handler h) {
Message m = obtain();
m.target = h;
return m;
}
关键是这句,m.target = h,赋值消息传送目标即为该Handler,而obtain()函数如下:如果消息池中不为空,则直接拿来使用,否则创建Message。
public static Message obtain() {
synchronized (sPoolSync) {
if (sPool != null) {
Message m = sPool;
sPool = m.next;
m.next = null;
sPoolSize--;
return m;
}
}
return new Message();
}
3)sendMessage或postMessage将Message插入队列恰当位置,但二者最后都是调用函数sendMessageAtTime,并通过enqueueMessage函数将信息Message在mQueue中确定位置、排队。
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
MessageQueue queue = mQueue;
if (queue == null) {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
return false;
}
return enqueueMessage(queue, msg, uptimeMillis);
}
继续寻找源码,发现enqueueMessage最终会调用MessageQueue中的enqueueMessage,即
boolean enqueueMessage(Message msg, long when) {
msg.when = when;
Message p = mMessages;
boolean needWake;
if (p == null || when == 0 || when < p.when) {
// New head, wake up the event queue if blocked.
msg.next = p;
mMessages = msg;
needWake = mBlocked;
} else {
// Inserted within the middle of the queue. Usually we don't have to wake
// up the event queue unless there is a barrier at the head of the queue
// and the message is the earliest asynchronous message in the queue.
needWake = mBlocked && p.target == null && msg.isAsynchronous();
Message prev;
for (;;) {
prev = p;
p = p.next;
if (p == null || when < p.when) {
break;
}
if (needWake && p.isAsynchronous()) {
needWake = false;
}
}
msg.next = p; // invariant: p == prev.next
prev.next = msg;
}
// We can assume mPtr != 0 because mQuitting is false.
if (needWake) {
nativeWake(mPtr);
}
}
return true;
}
依据处理时间when进行排队,when越小,Message在队列中越靠前。
4)Looper利用循环泵loop()循环抽取队列中的Message并处理界面交互
public static void loop() {
final MessageQueue queue = me.mQueue;
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
msg.target.dispatchMessage(msg);
}
}
分析代码,很容易发现Loop是一个循环,直到消息队列为空退出。若存在Message,则通过msg.target.dispatchMessage(msg)分发消息,看Message源码发现,msg.target即为Handler,所以查看Handler. dispatchMessage(msg)源码如下:
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
最终出现handleMessage(msg),处理与主线程的交互,这需要在主线程中重写。
整个源码过程示意图如下:
四、例子如下
很简单的例子,模拟下载并刷新下载进度及结果
package com.tz.anr;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends Activity {
protected static final int UPDATE_PROGRESS = 0;
protected static final int UPDATE_FINISH = 1;
private static final int UPDATE_ERROR = 2;
private ProgressBar pb;
private TextView tv_progress;
Handler handler = new Handler(){
public void handleMessage(android.os.Message msg) {
//2.收到子线程发过来的消息
//该方法是执行在主线程里面,所以可以直接操作UI
switch (msg.what) {
case UPDATE_PROGRESS:
int progress = msg.arg1;
//更新进度条
pb.setProgress(progress);
tv_progress.setText(progress+"%");
break;
case UPDATE_FINISH:
Toast.makeText(MainActivity.this, "下载完毕!", 0).show();
break;
case UPDATE_ERROR:
Toast.makeText(MainActivity.this, "下载出错!", 0).show();
break;
default:
break;
}
};
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
pb = (ProgressBar)findViewById(R.id.pb);
pb.setMax(100);
tv_progress = (TextView)findViewById(R.id.tv_porgress);
}
public void click(View v){
/**
* 开子线程:AsyncTask、Thread
* 模拟下载。
*/
try {
new Thread(new Runnable() {
@Override
public void run() {
int progress = 0;
while(progress<100){
try {
Thread.sleep(500);
progress += 10;
//1.子线程里面发送消息给主线程。
// Message msg = new Message();
Message msg = handler.obtainMessage();
//what:代表是谁发出的消息--标识符id
msg.what = UPDATE_PROGRESS;
//存放数据arg1,arg2,obj
// msg.arg2
// msg.obj = new Student();
msg.arg1 = progress;
handler.sendMessage(msg);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
// Message msg = handler.obtainMessage();
// //what:代表是谁发出的消息--标识符id
// msg.what = UPDATE_FINISH;
// handler.sendMessage(msg);
Message msg = handler.obtainMessage();
msg.sendToTarget();//这种方法只能使用handler.obtainMessage();
// handler.sendEmptyMessage(UPDATE_FINISH);
// handler.sendMessageDelayed(msg, delayMillis)//delayMillis延迟时间,多久以后发送该消息
// handler.sendMessageAtTime(msg, uptimeMillis)//uptimeMillis:可以在某个时间点发送该消息
}
}).start();
} catch (Exception e) {
e.printStackTrace();
// Message msg = handler.obtainMessage();
// //what:代表是谁发出的消息--标识符id
// msg.what = UPDATE_ERROR;
// handler.sendMessage(msg);
handler.sendEmptyMessage(UPDATE_ERROR);
}
}
}
最后
以上就是善良台灯为你收集整理的Handler消息(Message)传递机制详解的全部内容,希望文章能够帮你解决Handler消息(Message)传递机制详解所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复