android的消息处理
Looper类
Looper的字面意思是“循环者”,它被设计用来使一个普通线程变成Looper线程。所谓Looper线程就是循环工作的线程。在程序开发中(尤其是GUI开发中),我们经常会需要一个线程不断循环,一旦有新任务则执行,执行完继续等待下一个任务,这就是Looper线程。使用Looper类创建Looper线程很简单:
public class LooperThread extends Thread {
@Override
public void run() {
// 将当前线程初始化为Looper线程
Looper.prepare();
// ...其他处理,如实例化handler
// 开始循环处理消息队列
Looper.loop();
}
}
Looper.prepare()
源码
public class Looper {
// 每个线程中的Looper对象其实是一个ThreadLocal,即线程本地存储(TLS)对象
private static final ThreadLocal sThreadLocal = new ThreadLocal();
// Looper内的消息队列
final MessageQueue mQueue;
// 当前线程
Thread mThread;
// 。。。其他属性
// 每个Looper对象中有它的消息队列,和它所属的线程
private Looper() {
mQueue = new MessageQueue();
mRun = true;
mThread = Thread.currentThread();
}
// 我们调用该方法会在调用线程的TLS中创建Looper对象
public static final void prepare() {
if (sThreadLocal.get() != null) {
// 试图在有Looper的线程中再次创建Looper将抛出异常
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper());
}
// 其他方法
}
注意:
- 通过源码可以看出一个Thread只能有一个Looper对象,
- prepare方法核心就是将looper对象定义为ThreadLocal
Looper.loop()
public static final void loop() {
Looper me = myLooper(); //得到当前线程Looper
MessageQueue queue = me.mQueue; //得到当前looper的MQ
Binder.clearCallingIdentity();
final long ident = Binder.clearCallingIdentity();
// 开始循环
while (true) {
Message msg = queue.next(); // 取出message
if (msg != null) {
if (msg.target == null) {
// message没有target为结束信号,退出循环
return;
}
// 日志。。。
if (me.mLogging!= null) me.mLogging.println(
">>>>> Dispatching to " + msg.target + " "
+ msg.callback + ": " + msg.what
);
// 将真正的处理工作交给message的target,即handler
msg.target.dispatchMessage(msg);
// 还是日志。。。
if (me.mLogging!= null) me.mLogging.println(
"<<<<< Finished to " + msg.target + " "
+ msg.callback);
final long newIdent = Binder.clearCallingIdentity();
if (ident != newIdent) {
Log.wtf("Looper", "Thread identity changed from 0x"
+ Long.toHexString(ident) + " to 0x"
+ Long.toHexString(newIdent) + " while dispatching to "
+ msg.target.getClass().getName() + " "
+ msg.callback + " what=" + msg.what);
}
// 回收message资源
msg.recycle();
}
}
}
Looper.myLooper()
得到当前线程looper对象:
public static final Looper myLooper() {
// 在任意线程调用Looper.myLooper()返回的都是那个线程的looper
return (Looper)sThreadLocal.get();
}
Handler类
什么是handler?handler扮演了往MQ上添加消息和处理消息的角色(只处理由自己发出的消息),即通知MQ它要执行一个任务(sendMessage),并在loop到自己的时候执行该任务(handleMessage),整个过程是异步的。handler创建时会关联一个looper,默认的构造方法将关联当前线程的looper,不过这也是可以set的。
public class Handler {
final MessageQueue mQueue; // 关联的MQ
final Looper mLooper; // 关联的looper
final Callback mCallback;
// 其他属性
public Handler() {
if (FIND_POTENTIAL_LEAKS) {
final Class<? extends Handler> klass = getClass();
if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
(klass.getModifiers() & Modifier.STATIC) == 0) {
Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
klass.getCanonicalName());
}
}
// 默认将关联当前线程的looper
mLooper = Looper.myLooper();
// looper不能为空,即该默认的构造方法只能在looper线程中使用
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
// 重要!!!直接把关联looper的MQ作为自己的MQ,因此它的消息将发送到关联looper的MQ上
mQueue = mLooper.mQueue;
mCallback = null;
}
}
handler发送消息
public final boolean post(Runnable r)
{
// 注意getPostMessage(r)将runnable封装成message
return sendMessageDelayed(getPostMessage(r), 0);
}
private final Message getPostMessage(Runnable r) {
Message m = Message.obtain(); //得到空的message
m.callback = r; //将runnable设为message的callback,
return m;
}
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);
}
else {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
}
return sent;
}
handler发出的message有如下特点:
1.message.target为该handler对象,这确保了looper执行到该message时能找到处理它的handler,即loop()方法会调用Handler中的dispatchMessage方法。
msg.target.dispatchMessage(msg);
2.post发出的message,其callback为Runnable对象
Handler处理消息
// 处理消息,该方法由looper调用
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
// 如果message设置了callback,即runnable消息,处理callback!
handleCallback(msg);
} else {
// 如果handler本身设置了callback,则执行callback
if (mCallback != null) {
/* 这种方法允许让activity等来实现Handler.Callback接口,避免了自己编写handler重写handleMessage方法。见http://alex-yang-xiansoftware-com.iteye.com/blog/850865 */
if (mCallback.handleMessage(msg)) {
return;
}
}
// 如果message没有callback,则调用handler的钩子方法handleMessage
handleMessage(msg);
}
}
// 处理runnable消息
private final void handleCallback(Message message) {
message.callback.run(); //直接调用run方法!
}
// 由子类实现的钩子方法
public void handleMessage(Message msg) {
}
Message类
handler如果使用sendMessage的方式把消息入队到消息队列中,需要传递一个Message对象,而在Handler中,需要重写handleMessage()方法,用于获取工作线程传递过来的消息,
Message是一个final类,所以不可被继承。Message封装了线程中传递的消息,如果对于一般的数据,Message提供了getData()和setData()方法来获取与设置数据,其中操作的数据是一个Bundle对象,这个Bundle对象提供一系列的getXxx()和setXxx()方法用于传递基本数据类型的键值对。
还有另外一种方式在Message中传递对象,那就是使用Message自带的obj属性传值,它是一个Object类型,所以可以传递任意类型的对象,Message自带的有如下几个属性:
- int arg1:参数一,用于传递不复杂的数据,复杂数据使用setData()传递。
- int arg2:参数二,用于传递不复杂的数据,复杂数据使用setData()传递。
- Object obj:传递一个任意的对象。
- int what:定义的消息码,一般用于设定消息的标志。
对于Message对象,一般并不推荐直接使用它的构造方法得到,而是建议通过使用Message.obtain()这个静态的方法或者Handler.obtainMessage()获取。Message.obtain()会从消息池中获取一个Message对象,如果消息池中是空的,才会使用构造方法实例化一个新Message,这样有利于消息资源的利用。并不需要担心消息池中的消息过多,它是有上限的,上限为10个。Handler.obtainMessage()具有多个重载方法,如果查看源码,会发现其实Handler.obtainMessage()在内部也是调用的Message.obtain()。
总结
1.尽管Message有public的默认构造方法,但是你应该通过Message.obtain()来从消息池中获得空消息对象,以节省资源。
2.如果你的message只需要携带简单的int信息,优先使用Message.arg1和Message.arg2来传递信息,这比用Bundle更省内存,使用obj便可携带Object类型数据。
3.用message.what来标识信息,以便用不同方式处理message。
关系
Handler、Looper、MessageQueue、Message这三者之间的关系如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dBzXVATp-1647927947724)(img/331079-20170217101714472-996967958.jpg)]
线程通信
1.子线程向主线程通信
handler = new Handler(Looper.myLooper()) {
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
if (msg.what == 0) {
tv_test1.setText("0");
}
}
};
btn_begin.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
new Thread(new Runnable() {
@Override
public void run() {
Looper.prepare();
handler.sendEmptyMessage(0);
Looper.loop();
}
}).start();
}
});
2.子线程和子线程之间的通信
public void onClick(View v) {
new Thread(new Runnable() {
@Override
public void run() {
Log.d(TAG, "runA: ");
Looper.prepare();
handler1 = new Handler(Looper.myLooper()) {
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
Log.d(TAG, "handleMessageA: ");
if (msg.what == 10) {
tv_test1.setText("B");
}
}
};
Looper.loop();
}
}).start();
class ThreadHandleB extends Thread {
@Override
public void run() {
super.run();
Log.d(TAG, "runB: ");
Looper looper = Looper.myLooper();
Message message = handler1.obtainMessage();
message.what = 10;
handler1.sendMessage(message);
}
}
3.主线程向子线程通信
btn_begin.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
ThreadHander threadHander1 = new ThreadHander();
threadHander1.start();
}
});
class ThreadHander extends Thread {
private Handler handler1;
private Handler handler2;
@Override
public void run() {
super.run();
Looper.prepare();
handler1 = new Handler(Looper.myLooper()) {
@Override
public void handleMessage(@NonNull Message msg) {
Log.d(TAG, "handleMessage1: ");
if (msg.what == 1) {
tv_test1.setText("handler1");
}
}
};
handler1.sendEmptyMessage(1);
handler2 = new Handler(Looper.myLooper()) {
@Override
public void handleMessage(@NonNull Message msg) {
Log.d(TAG, "handleMessage2: ");
if (msg.what == 2) {
tv_test2.setText("handler2");
}
}
};
handler2.sendEmptyMessage(2);
Message message1 = Message.obtain();
message1.what = 1;
handler1.sendMessage(message1);
Looper.loop();
}