标签: 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);
网友评论
这说的是啥意思?后面那句"如果为空"说的是什么为空
场景:一个Activity的主线程中有两个Handler(handler1,handler2),分别有自己的handMessage(Messgae msg)方法, 想用handler2发送消息,在handler1中收到,代码大致如下:
Message msg = Message.obtain();
msg.setTarget(handler1);
handler2.sendMessage(msg);
发现仍旧在handler2的handMessgae方法中获取到了该消息,也就是说msg.setTarget(handler1);这句代码无效。请问这怎么回事?