对android开发了解多一些的开发者应该都知道handler在android中的重要性。
Android中的消息机制是针对某一个具体线程的。一个线程只能有一个looper,通过looper来不停取出消息队列中的消息。
在默认创建的线程中是不具备消息队列和消息循环的,如果想让其被这些功能,需要调用Looper.prepare()绑定Looper实例,调用Looper.loop()进入消息循环。
由非UI线程如何与UI线程通信部分我们看出UI线程中有两个原则:
1.不要阻塞ui线程
2.不要在非ui线程修改ui线程元素
那么问题来了:在子线程中进行耗时操作后如何将通知ui线程更新数据呢?这就是handler机制的主要用途。
官方文档给出的用途有两个:
1.在ui线程未来的某个时间点调度message和runnables(postAtTime,postDelay,sendMessageAtTime等);
2.让一个action在另一个子线程中运行(子线程中执行耗时操作,完成之后通知UI thread更新)。
6.1 常见用法
先介绍一下与之配合使用的几个重要概念:
6.1.1 Message和Message队列
message是一个可以包含描述和任意类型数据对象的类,可以将Message发送给handler进行处理。下面从代码角度来分析一下:
1.它实现了Parcelable接口,可以用于系统之间传递数据: public final class Message implements Parcelable;
2.比较中要的成员变量:Handler target(处理该message的handler),Runnable callback(定义runnable,主要作用是将Runnable可以封装成message对象来处理,后面有分析),pubic int what(指明消息类型,使用较多),,public Object obj(可以是的任意对象);
3 如何创建message对象:虽然提供了public 构造方法,但是建议使用Message.obtain()或者Message.obtain(Message)。因为内部使用了message池,避免了过多的创建message对象。上源码:
- //Return a new Message instance from the global pool. Allows us to avoid allocating new objects in many cases.
- public static Message obtain() {
- synchronized (sPoolSync) {
- if (sPool != null) {
- Message m = sPool;
- sPool = m.next;
- m.next = null;
- sPoolSize--;
- return m;
- }
- }
- return new Message();
- }
//Return a new Message instance from the global pool. Allows us to avoid allocating new objects in many cases.
public static Message obtain() {
synchronized (sPoolSync) {
if (sPool != null) {
Message m = sPool;
sPool = m.next;
m.next = null;
sPoolSize--;
return m;
}
}
return new Message();
}
它还重载了很多方法,都是调用obtain来实现的如:public static Message obtain(Message)
- /**
- * Same as {@link #obtain()}, but copies the values of an existing message (including its target) into the new one.
- * @param orig Original message to copy.
- * @return A Message object from the global pool.
- */
- public static Message obtain(Message orig) {
- Message m = obtain();
- m.what = orig.what;
- m.arg1 = orig.arg1;
- m.arg2 = orig.arg2;
- m.obj = orig.obj;
- m.replyTo = orig.replyTo;
- if (orig.data != null) {
- m.data = new Bundle(orig.data);
- }
- m.target = orig.target;
- m.callback = orig.callback;
- return m;
- }
/**
* Same as {@link #obtain()}, but copies the values of an existing message (including its target) into the new one.
* @param orig Original message to copy.
* @return A Message object from the global pool.
*/
public static Message obtain(Message orig) {
Message m = obtain();
m.what = orig.what;
m.arg1 = orig.arg1;
m.arg2 = orig.arg2;
m.obj = orig.obj;
m.replyTo = orig.replyTo;
if (orig.data != null) {
m.data = new Bundle(orig.data);
}
m.target = orig.target;
m.callback = orig.callback;
return m;
}
再看看如果回收:
- // Return a Message instance to the global pool. You MUST NOT touch the Message after calling this function -- it has effectively been freed.
- public void recycle() {
- clearForRecycle();
- synchronized (sPoolSync) {
- if (sPoolSize < MAX_POOL_SIZE) {
- next = sPool;
- sPool = this;
- sPoolSize++;
- }
- }
- }
// Return a Message instance to the global pool. You MUST NOT touch the Message after calling this function -- it has effectively been freed.
public void recycle() {
clearForRecycle();
synchronized (sPoolSync) {
if (sPoolSize < MAX_POOL_SIZE) {
next = sPool;
sPool = this;
sPoolSize++;
}
}
}
4.sentToTarget函数:
- public void setTarget(Handler target) {
- this.target = target;
- }
public void setTarget(Handler target) {
this.target = target;
}
实际上就是设置自己的成员变量target
MessageQueue顾名思义就是Message队列
着重分析两个函数
1 enqueueMessage(Message msg,long when)
- final boolean enqueueMessage(Message msg, long when) {
- ...
- final boolean needWake;
- synchronized (this) {
- msg.when = when;
- //Log.d("MessageQueue", "Enqueing: " + msg);
- Message p = mMessages;
- if (p == null || when == 0 || when < p.when) {
- msg.next = p;
- mMessages = msg;
- needWake = mBlocked; // new head, might need to wake up
- } else {
- Message prev = null;
- while (p != null && p.when <= when) {
- prev = p;
- p = p.next;
- }
- msg.next = prev.next;
- prev.next = msg;
- needWake = false; // 按照顺序排列,时间小的排在队首
- }
- }
- if (needWake) {
- nativeWake(mPtr);
- }
- return true;
- }
final boolean enqueueMessage(Message msg, long when) {
...
final boolean needWake;
synchronized (this) {
msg.when = when;
//Log.d("MessageQueue", "Enqueing: " + msg);
Message p = mMessages;
if (p == null || when == 0 || when < p.when) {
msg.next = p;
mMessages = msg;
needWake = mBlocked; // new head, might need to wake up
} else {
Message prev = null;
while (p != null && p.when <= when) {
prev = p;
p = p.next;
}
msg.next = prev.next;
prev.next = msg;
needWake = false; // 按照顺序排列,时间小的排在队首
}
}
if (needWake) {
nativeWake(mPtr);
}
return true;
}
可以看出队列是按照时间前后顺序的,时间小的在队首。
2 next()从队列中取出来一个message
- final Message next() {
- for (;;) {//不停循环取数据
- ...
- nativePollOnce(mPtr, nextPollTimeoutMillis);
- synchronized (this) {
- // Try to retrieve the next message. Return if found.
- final long now = SystemClock.uptimeMillis();
- final Message msg = mMessages;
- if (msg != null) {
- final long when = msg.when;
- if (now >= when) {//如果时间该message已经到了到执行时间
- mBlocked = false;//不阻塞
- mMessages = msg.next;//队尾指向下一个
- msg.next = null;//标记正在使用
- if (false) Log.v("MessageQueue", "Returning message: " + msg);
- msg.markInUse();
- return msg;
- } else {
- nextPollTimeoutMillis = (int) Math.min(when - now, Integer.MAX_VALUE);//下一次pool时间间隔,native层调用
- }
- } else {
- nextPollTimeoutMillis = -1;
- }
- ...
- }
- }
final Message next() {
for (;;) {//不停循环取数据
...
nativePollOnce(mPtr, nextPollTimeoutMillis);
synchronized (this) {
// Try to retrieve the next message. Return if found.
final long now = SystemClock.uptimeMillis();
final Message msg = mMessages;
if (msg != null) {
final long when = msg.when;
if (now >= when) {//如果时间该message已经到了到执行时间
mBlocked = false;//不阻塞
mMessages = msg.next;//队尾指向下一个
msg.next = null;//标记正在使用
if (false) Log.v("MessageQueue", "Returning message: " + msg);
msg.markInUse();
return msg;
} else {
nextPollTimeoutMillis = (int) Math.min(when - now, Integer.MAX_VALUE);//下一次pool时间间隔,native层调用
}
} else {
nextPollTimeoutMillis = -1;
}
...
}
}
6.1.2 Runnable
实际可以看成是message。看看Handler中是如何处理的post(Runnable)
- public final boolean post(Runnable r)
- {
- return sendMessageDelayed(getPostMessage(r), 0);
- }
public final boolean post(Runnable r)
{
return sendMessageDelayed(getPostMessage(r), 0);
}
调用的是处理message的方法,再看getPostMessage(Runnable):
- private final Message getPostMessage(Runnable r) {
- Message m = Message.obtain();
- m.callback = r;
- return m;//仍然是作为一个Message对象来处理
- }
private final Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;//仍然是作为一个Message对象来处理
}
尼玛,真省事,就是将Runnable包装到message中,作为该message一个成员变量,实际上还是作为一个Message对象来处理。
6.1.3 Looper
不断的将messageQueue中的信息取出来执行
重要的变量:
1. static final ThreadLocal<Looper> sThreadLocal;用来存放和线程相关的信息。也就是将线程和Looper绑定到一起。
2. final MessageQueue mQueue 要操作的消息队列。也就是一个looper对应一个messageQuene
重要方法:
1 public static void prepare:
- /** Initialize the current thread as a looper. This gives you a chance to create handlers that then reference this looper, before actually starting the loop. Be sure to call {@link #loop()} after calling this method, and end it by */calling {@link #quit()}.
- public static void prepare() {
- if (sThreadLocal.get() != null) {
- throw new RuntimeException("Only one Looper may be created per thread");
- }
- sThreadLocal.set(new Looper());
- }
/** Initialize the current thread as a looper. This gives you a chance to create handlers that then reference this looper, before actually starting the loop. Be sure to call {@link #loop()} after calling this method, and end it by */calling {@link #quit()}.
public static void prepare() {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper());
}
就是将Thread 和looper进行绑定。可以看出一个线程有且只能有一个looper。在和线程进行绑定时调用了Looper的构造方法Looper()构造了一个Looper实例:
- private Looper() {
- mQueue = new MessageQueue();
- mRun = true;
- mThread = Thread.currentThread();
- }
private Looper() {
mQueue = new MessageQueue();
mRun = true;
mThread = Thread.currentThread();
}
初始化messagequeue,将当前线程赋值给looper对象mThread变量。
再看looper()函数:
2 public static void loop()
- public static void loop() {
- //先判断是否绑定了looper,如果该线程没有绑定Looper对象,则提示应该先调用prepare方法。
- Looper me = myLooper();
- if (me == null ) {
- throw new RuntimeException( "No Looper; Looper.prepare() wasn't called on this thread.");
- }
- MessageQueue queue = me. mQueue;
- while (true ) {
- //从queue中取message并进行分发message
- Message msg = queue.next(); // might block
- if (msg != null ) {
- if (msg.target == null) {
- // No target is a magic identifier for the quit message.
- return ;
- }
- //分发message
- msg.target.dispatchMessage(msg);
- //回收
- msg.recycle();
- }
- }
- }
public static void loop() {
//先判断是否绑定了looper,如果该线程没有绑定Looper对象,则提示应该先调用prepare方法。
Looper me = myLooper();
if (me == null ) {
throw new RuntimeException( "No Looper; Looper.prepare() wasn't called on this thread.");
}
MessageQueue queue = me. mQueue;
while (true ) {
//从queue中取message并进行分发message
Message msg = queue.next(); // might block
if (msg != null ) {
if (msg.target == null) {
// No target is a magic identifier for the quit message.
return ;
}
//分发message
msg.target.dispatchMessage(msg);
//回收
msg.recycle();
}
}
}
先看myLooper():就是返回线程所绑定的looper实例,可以看出如果没有绑定则报错。
再看dispatchMessage(msg)这个方法实际是Handler类中定义的(message中的target对象就是Handler类型)。
3 public void dispatchMessage(Message msg)
- public void dispatchMessage(Message msg) {
- if (msg.callback != null) {
- handleCallback(msg);//如果msg.callback!=null,执行handleCallback(msg)方法,此方法的实现就是:message.callback.run()
- } else {
- if (mCallback != null) {
- if (mCallback.handleMessage(msg)) {//如果在创建handler时已经执行了callback,这执行该callback的handleMessage方法
- return;
- }
- }
- handleMessage(msg);//msg中没有定义callback(Runnable)时才执行handleMessage方法,我们可以override此方法
- }
- }
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);//如果msg.callback!=null,执行handleCallback(msg)方法,此方法的实现就是:message.callback.run()
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {//如果在创建handler时已经执行了callback,这执行该callback的handleMessage方法
return;
}
}
handleMessage(msg);//msg中没有定义callback(Runnable)时才执行handleMessage方法,我们可以override此方法
}
}
其中 mCallback 是Callback类型:
- public interface Callback {
- public boolean hanleMessage(Message msg);
- }
public interface Callback {
public boolean hanleMessage(Message msg);
}
4 Looper中还有一个重要的方法,这个方法一般不用,但在后面的分析中会涉及到:prepareMainLooper()
我们在主线程中创建looper对象时并没有主动调用prepare方法,是因为这里已经实例化一个mainLooper对象给主线程使用。
6.1.4 Handler类
handler类的主要作用就是发送和处理message对象的。
先看看有哪些重要的成员变量
1 final Looper mLooper:该线程绑定的Looper实例
2 final MessageQueue mQueue:mLooper中的成员变量
3 final Callback mCallback:自定义handleMessage方法接口
再来看重要的方法
1 构造方法:public Handler(),
- public Handler(){
- //..
- mLooper=Looper.myLooper();//获得该线程绑定的Looper实例
- if(mLooper==null){
- throw new RuntimeException("Can't create handler inside thread that has not called Looper.prepare()");
- }
- mQueue = mLooper.mQueue;
- mCallback=null;
- }
public Handler(){
//..
mLooper=Looper.myLooper();//获得该线程绑定的Looper实例
if(mLooper==null){
throw new RuntimeException("Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback=null;
}
2 带参数的构造方法:public Handler(Looper,Callback)
- public Handler(Looper looper,Callback callback){
- mLooper=looper;
- mQueue = looper.mQueue;
- mCallback= callback;
- }
public Handler(Looper looper,Callback callback){
mLooper=looper;
mQueue = looper.mQueue;
mCallback= callback;
}
3 发送消息(Runnable实际上也是消息,这里不再分析),有好几种方式,最终都是sendMessageAtTime(Message,Long)
- public boolean sendMessageAtTime(Message msg, long uptimeMillis)
- {
- boolean sent = false ;
- MessageQueue queue = mQueue;
- if (queue != null) {
- msg.target = this ;//该message对象的target成员变量设置为此handler实例
- sent = queue.enqueueMessage(msg, uptimeMillis);//调用messageQueue来讲message加入队列
- }
- else {
- RuntimeException e = new RuntimeException(
- this + " sendMessageAtTime() called with no mQueue");
- Log. w("Looper", e.getMessage(), e);
- }
- return sent;
- }
public boolean sendMessageAtTime(Message msg, long uptimeMillis)
{
boolean sent = false ;
MessageQueue queue = mQueue;
if (queue != null) {
msg.target = this ;//该message对象的target成员变量设置为此handler实例
sent = queue.enqueueMessage(msg, uptimeMillis);//调用messageQueue来讲message加入队列
}
else {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log. w("Looper", e.getMessage(), e);
}
return sent;
}
4 handleMessage(Message)
根据取出来的message对象进行消息处理,一般override
典型用法:
1.子线程中:
- class MyThread extends Thread{
- public Handler mHanlder;
- public void run(){
- //将线程与Looper绑定。
- //此方法必须在handler创建之前调用,handler否则实例化报错
- Looper.prepare();
- mHandler = new Handler(){
- public void handleMessage(Message msg){
- //处理消息
- }
- };
- //不停的取出该线程中message队列中的消息。
- Looper.loop();
- }
- }
class MyThread extends Thread{
public Handler mHanlder;
public void run(){
//将线程与Looper绑定。
//此方法必须在handler创建之前调用,handler否则实例化报错
Looper.prepare();
mHandler = new Handler(){
public void handleMessage(Message msg){
//处理消息
}
};
//不停的取出该线程中message队列中的消息。
Looper.loop();
}
}
2.主线程中直接实例化Handler,这里简要介绍一个为什么不需要Looper.prepare和Looper.loop.
是因为在程序启动已经做了这些工作,在ActivityThread类中main方法:
- public static void main(String[] args) {
- Looper.prepareMainLooper();
- if (sMainThreadHandler == null) {
- sMainThreadHandler = new Handler();
- }
- Looper.loop();
- }
public static void main(String[] args) {
Looper.prepareMainLooper();
if (sMainThreadHandler == null) {
sMainThreadHandler = new Handler();
}
Looper.loop();
}
6.2 流程分析
下面以一个具体案例来分析怎么调用的:
比如说在子线程中发送一个消息给UI线程
首先UI线程中定义了一个Handler:
- private Handler handler = new Handler(){
- public void handleMessage(Message msg){
- if(msg.what=1){
- tv.setText("数据下载完毕");
- }
- }
- };
private Handler handler = new Handler(){
public void handleMessage(Message msg){
if(msg.what=1){
tv.setText("数据下载完毕");
}
}
};
需要在子线程中执行耗时操作:
- new Thread(){
- public void run(){
- try{
- //模拟耗时操作
- Thread.sleep(10*1000);
- //发送消息,通知UI线程更新
- handler.sendEmptyMessage(1);
- }catch(Exception e){
- }
- }
- }.start();
new Thread(){
public void run(){
try{
//模拟耗时操作
Thread.sleep(10*1000);
//发送消息,通知UI线程更新
handler.sendEmptyMessage(1);
}catch(Exception e){
}
}
}.start();
流程分析:
1该UI线程中的Looper.prepareMainLooper();和 Looper.loop(); 执行,这样就不需要在实例化handler时调用了prepare和looper。线程中已经有一个looper实例,且已经开始不停的从messageQueue中读取message。
2.子线程中给通过UI线程的handler变量调用handler.sendMessage系类方法,给Ui线程的消息队里发送一个消息。
3.Looper.loop方法调用messageQueue的next()方法取消息,取出来之后调用handler的dispatchMessage方法。
4.执行dispatchMessage方法,由于message中callback ==null,所以执行override的handleMessage方法,更新textview。
版权声明:本文为博主原创文章,未经博主允许不得转载。