标签: android 线程 handler
1 什么是handler
Handler中文翻译为“处理者”,这里的“处理”顾名思义是在某种条件发生之后所要进行的操作。
2 handler的作用
- Handler主要用于异步线程进行通信。这种方式也是Android官方推荐的方式,比较节省性能。我们知道,Android主线程(UI线程)主要负责UI绘制,耗时操作不能放在主线程执行,要不然容易造成卡顿,严重时会ANR。在Android中最常使用Handler的场景就是主线程调用子线程去进行网络访问,子线程在获取到网络访问的返回结果并处理数据之后,通知主线程去更新UI。例如下拉刷新。Handler在这里充当的是消息的发送者和接收者的角色。所谓消息,也就是前面讲的某种特定条件发生之后的状态。例如获取完网络数据之后,获取数据成功或者失败,就是不同的状态,需要发送不同的消息。
- 另外,Handler还用于延时处理某个任务。
3 Handler的使用原理
- Handler既是发送者也是接收处理者,一个消息发送出来,交由哪个Handler去处理,这个完全取决于这个消息的发送者是哪个Handler。即一个Handler发送的消息,只能交由自己去处理。要做到异步线程进行通信,关键在于在A线程中拿到B线程的Handler,拿到之后就可以使用B线程的Handler去发送消息,交由B线程去处理消息了。线程与Handler之间是多对一的关系,一个线程可以有多个Handler,一个Handler只能且必须绑定一个线程。一个线程有多个Handler(使用场景会在后面介绍),用于处理不用类型的消息。
- 使用Handler的表现形式有两种:
(1)通过发送消息(sendMessage方法)接收消息(接收消息即回调该Handler的handleMessage方法)并处理的形式;
(2)通过发送Runnable对象的形式,直接让该Handler所在线程执行其run方法。即调用post(Runnabler)方法。需要注意的是:(1)该Runnable也会被包装成一个消息的形式进行传递。(2)整个过程并没有另外新建线程,该Runnable在Handler所在线程执行。
4 Handler相关概念
4.1 Message
Message用来记录需要传递的信息。该类继承自Parcelable类。
官方描述为:
/**
Defines a message containing a description and arbitrary data object that can be
sent to a {@link Handler}. This object contains two extra int fields and an
extra object field that allow you to not do allocations in many cases.
While the constructor of Message is public, the best way to get
one of these is to call {@link #obtain Message.obtain()} or one of the
{@link Handler#obtainMessage Handler.obtainMessage()} methods, which will pull
them from a pool of recycled objects.
*/Message类默认定义了两个int和一个Object(传递对象)用于传输常用的数据,如果不够用,则使用Bundle。
public final class Message implements Parcelable {
/**
* User-defined message code so that the recipient can identify
* what this message is about. Each {@link Handler} has its own name-space
* for message codes, so you do not need to worry about yours conflicting
* with other handlers.
*/
public int what;
/**
* arg1 and arg2 are lower-cost alternatives to using
* {@link #setData(Bundle) setData()} if you only need to store a
* few integer values.
*/
public int arg1;
/**
* arg1 and arg2 are lower-cost alternatives to using
* {@link #setData(Bundle) setData()} if you only need to store a
* few integer values.
*/
public int arg2;
/**
* An arbitrary object to send to the recipient. When using
* {@link Messenger} to send the message across processes this can only
* be non-null if it contains a Parcelable of a framework class (not one
* implemented by the application). For other data transfer use
* {@link #setData}.
*
* <p>Note that Parcelable objects here are not supported prior to
* the {@link android.os.Build.VERSION_CODES#FROYO} release.
*/
public Object obj;
- 另外,还定义了一个target,表示与该Message绑定的Handler。一个callback,当使用post(Runnable r)时,r会被包装成员一个Message,这个Message的callback就是传入的r。
4.2 MessageQueue
Handler发送的消息,可以立即处理也可以延时处理,肯定需要一个容器来存放消息。MessageQueue就是这样一个消息队列。
4.3 Looper
Message被Handler发送出来,会被放入MessageQueue中,放入其中的Message在条件成熟的时候会被取出来,交由Handler去处理。整个过程中还需要一个对象来执行获取并放入,取出并交给对应Handler的工作。这个工作就由Looper来完成。
Looper需要执行两个过程:(1)与线程进行绑定prepare方法(2)读取消息队列中的消息并交由Handler进行处理loop方法。
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}
** 4.4 整个过程
- 一个线程对应一个Looper、一个MessageQueue以及多个Handler、多个Message
- 一个Message对象,在被发送的时候将发送该Message对象的Handler对象的引用保存到target成员变量上,looper在轮询Message的时候,就直接把该Message交给message.target这个Handler去处理就可以了。
- 在调用Handler的sendMessage后,会把Message对象放入一个MessageQueue队列,该队列属于某个Looper对象,每个Looper对象通过 ThreadLocal.set(new Looper())跟一个Thread绑定了。Looper对象所属的线程在Looper.Loop方法中循环执行如下步骤:从MessageQueue队列读取 Message对象,并把Message对象交由Handler处理,调用Handler的dispatchMessage方法。
5 Handler的使用步骤
5.1 获取Handler
- 当前Thread已经有Looper的情况(主线程默认已经在ActivityThread的main方法中初始化Looper),则直接new一个Handler。可以选择重写或者不重写handleMessage方法(不重写将只能使用post的方式调用)。此时该Handler会自动绑定到当前线程。
官方解释为:
/**
* Default constructor associates this handler with the {@link Looper} for the
* current thread.
*
* If this thread does not have a looper, this handler won't be able to receive messages
* so an exception is thrown.
*/
public Handler() {
this(null, false);
}
/**
* Subclasses must implement this to receive messages.
*/
public void handleMessage(Message msg) {
}
实例:
public class MyActivity extends BaseActivity{
private static final String TAG = "MyActivity";
Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case CommonConstants.MSG_REFRESH_VIDEO_ITEM:
doSomething();
break;
default:
break;
}
}
};
- 当前线程还没有Looper的情况,则需要先初始化当前线程的Looper,然后new一个Handler。
初始化当前Looper的方式为:
* class LooperThread extends Thread {
* public Handler mHandler;
*
* public void run() {
/** 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()}.
*/
* Looper.prepare();
*
* mHandler = new Handler() {
* public void handleMessage(Message msg) {
* // process incoming messages here
* }
* };
*
/**
* Run the message queue in this thread. Be sure to call
* {@link #quit()} to end the loop.
*/
* Looper.loop();
* }
* }
在初始化Handler之前需要调用Lopper.prepare()方法初始化Looper,初始化Handler之后调用Looper.loop()开始轮询消息。
- 如果在子线程使用主线程的Handler,可以使用new Handler(Looper.getMainLooper())的方法得到。
5.2 使用Handler发送消息
handler发送消息的方法是比较多,常用的就包括
获取消息包括Runnable对象和message对象两种,获取Message的方式包括:
1 直接new一个Message,设置what等参数(不推荐)。
2 通过handler获取复用的Message(推荐)
- handler.obtainMessage()
- handler.obtainMessage(int what)
- obtainMessage(int what, Object obj)
- ......
3 直接发送空Message,只有what
- sendEmptyMessage(int what)
发送消息的方法:
post(Runnable)
postAtTime(Runnable,long)
postDelayed(Runnable long)
sendEmptyMessage(int)
sendMessage(Message) 将消息发送到消息队列
msg.sendToTarget() 将消息发送到消息队列
sendMessageAtTime(Message,long) 定时将消息发送到消息队列
sendMessageDelayed(Message,long) 延迟一定时间后,将消息发送到消息队列
5.3 使用Handler接收消息并处理
在Handler的handlerMessage中根据what去处理相应逻辑。
6 发送Runnable和发送Message的区别
post方式:发送runnable,实际上是把runnable对象设置为一个Message的成员变量callback之后,发送该Message。最后都是走到sendMessageDelayed方法当中。唯一的区别在于,post方式的Message的callback不是null,send方式发送的Message的callback是null。
1
public final boolean post(Runnable r){
return sendMessageDelayed(getPostMessage(r), 0);
}
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}
2
public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
send方式:
1
public final boolean sendMessage(Message msg)
{
return sendMessageDelayed(msg, 0);
}
2
public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
Looper在处理的时候:如果msg.callback的是null,则直接调用其run方法;如果为空,则交由handlerMessage去处理。
1
public static void loop() {
...
try {
msg.target.dispatchMessage(msg);
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
...
}
2
/**
* Handle system messages here.
*/
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
7 实例
实例1:handler定时器
需求:在主线程每隔一段时间执行一次
代码:
1
private static long mDelayMillis = 1000;
Handler mHandler = new Handler(Lopper.getMainLooper());
Runnable runnable = new Runnable() {
@Override
public void run() {
...
mHandler.postDelayed(this, mDelayMillis);
};
mHandler.post(runnable);
//如果要取消任务
mHandler.removeCallbacks(runnable);