Android消息处理
1、消息:Message的常用属性
what:消息号
//注意:target是default权限,即只有android.os这个packages内才可以访问;
//只能用Hanler.obtainMessage()或Message.obtainMessage (handler,)
target:处理该消息的Handler;
callback:消息的回调
arg1,arg2:默认的int型数据体
尽量通过Handler.obtainMessage ()来生成消息。
2、消息队列: MessageQueue
enqueueMessage():向队列发送消息
尽量通过Handler来发送和删除消息。
3、消息循环:Looper
-
Looper组合了Thread和MessageQueue。
-
Android的消息循环是针对线程的,但线程可以有消息循环,也可以没有;有消息循环的线程一般都会有一个Looper,并且只能有一个Looper。
-
主线程(UI线程)自带消息循环,所有的应用组件----包括Activity、Service、Broadcast Receiver都在应用程序的主线程中运行。
Activity启动时,系统会为其创建消息队列和消息循环:通过AcitivityManagerService进程的startActivity>>startProcess,创建用户Process和ActivityThread,ActivityThread组合了 Looper和Handler的子类H,不展开。
-
创建的工作线程默认没有消息队列和消息循环,要进行消息处理,有以下2种方式:
1)为工作线程创建独立的消息循环。
2)把消息放入主线程的消息队列中,在主线程中处理:因为主线程一般负责视图组件的更新操作,对于不是线程安全的视图组件来说,这种方式能够很好的实现视图的更新。
-
尽量使用HandlerThread来为工作线程创建消息循环,可以避免线程的同步问题,需特别留意自带消息循环线程的生命周期,不要滥用。
-
通过Looper.myLooper()可以得到当前线程的Looper对象,通过Looper.getMainLooper()得到当前进程的主线程的Looper对象。
-
使用Looper已经足够完成向指定线程发送消息的工作:
1)获取指定线程的Looper对象--mLooper。
2)定义好Message对象:
Message msg = Message.obtain(); msg.what = 1; msg.arg1 = 2; msg.arg2 = 3; msg.target = handler;//目标线程的handler
……
3)直接调用目标线程的消息队列,发送消息:
但这种方式比较繁琐,容易出错,且无法自定义消息的处理回调,因此使用Handler类来简化。
-
mLooper.myQueue.enqueueMessage(msg,0);
-
Looper在loop()循环中处理消息,对每一条消息调用:
msg.target.dispatchMessage(msg);
target是一个Handler对象,一个Looper可以对应多个Handler,在各自的线程Handler中处理自定义消息。
4、工具辅助:Handler
-
Handler运行在创建它的线程中,如果在handleMessage 中进行耗时的操作,会阻塞创建它的线程。
-
Handler应该由处理消息的线程创建:
class LooperThread extends Thread {
public Handler mHandler;
public void run() {
Looper.prepare();
mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
// process incoming messages here
}
};
Looper.loop();
}
}
并不意味着每个Handler都需要独立的线程,可以在一个线程中创建多个Handler。常见的例子是在自定义控件中增加Handler来更新UI,这些自定义控件的Handler都将在UI线程创建。
-
工作线程生成Handler前,务必确保该线程已经建立一个Looper,否则会报错。
-->Handler 对象构造时,如果不带Looper参数、不在主线程中,则需要先调用Looper.prepare(),以便为工作线程创建独立的消息循环;
-->Handler 对象构造时,如果是在主线程中(比如在自定义控件中定义的Handler)、不带Looper参数,则代表使用主线程的消息循环;
-->Handler 对象构造时,带有Looper参数,则代表使用Looper对应的目标线程的消息循环;
-
Looper.loop()后的代码,只会在生成的Looper退出后,才会被调用。
-
Handler对象以目标线程的Looper创建时,那么当调用Handler的sendMessage方法,系统就会把消息发送到目标线程的消息队列,在调用handleMessage方法时处理目标线程消息队列中的消息。
-
注意带消息循环的工作线程的生命周期。
4、几个要点
-
尽可能的使用Handler来简化代码处理。
-
Looper总是依附于一个Thread,为这个线程开启消息循环,根据队里中每条消息的target派发消息。
主线程由系统自动创建Looper;
工作线程需要通过Looper.prepare()手工创建Looper。
尽量使用HandlerThread来为工作线程创建消息循环,可以避免线程的同步问题。
-
一个Looper可以对应多个Handler,每一个Handler都可以自定义消息、处理消息,共享同一个消息循环和消息队列;并非每一个Handler都需要启动一个独立的线程(大多情况下也不会)。
-
发送到队列里的消息必须要指定处理的Handler(通过msg.tagget),调用指定Handler的dispatchMessage() 来处理消息,按照以下优先级:
如果消息自带callback,则调用callback;
如果Handler定义了mCallBack,则调用mCallBack;
调用Handler重载的handleMessage。
-
利用以上特性,可以通过Handler创建特殊的线程队列,定时开启线程。
private Runnable mRunnable = new Runnable() {
@Override
public void run() {
mHandler.postDelayed(this, 1000);
// do sth here
}
};
-
Handler运行在创建它的线程中,如果在handleMessage 中进行耗时的操作,会阻塞创建它的线程,所以不要在主线程创建的的handler中进行耗时操作。
5、在工作线程安全的更新UI
Activity.runOnUiThread(Runnable)
View.post(Runnable)
View.postDelayed(Runnable, long)
发送消息给 在UI线程中创建的Handler