Hanlder是安卓中重要的一个类,自己分析一下,也供大家参考。
Handler是什么:
- 一个handler允许你发送和传递消息和Runnable对象,并且和一个MessageQueue相联系
- 每个handler实例和一个单线程并且和此线程的MessageQueue相关联
- 当你创建一个handler的时候,它就和这个线程绑定起来,也和这个线程所创建的MessageQueue绑定起来(从此时起,他将会调度Message和Runable 到MessageQueue消息队列,当他们从消息队列出来的时候,将执行他们。)
Handler两个主要作用是什么:
- 编排消息和runnables以便将来执行
- 在与您自己的线程不同的线程上执行一个操作。
首先打开handler源码,我们先弄清里面的包含的方法:
里面一个Callback接口
/**
* Callback interface you can use when instantiating a Handler to avoid
* having to implement your own subclass of Handler.
* Callback接口是,当你实例化一个handler的时候,为了避免你自己实现Handler的子类
*
* @return True 如果不需要进一步的处理
*/
public interface Callback {
public boolean handleMessage(Message msg);
}
七个构造方法,即一个空的构造方法以及Looper,Callback,boolean三个类型参数的任意组合,2的3次方个。但其中,带boolean参数的构造方法,都被加了@hide隐藏掉了,所以我们基本没自己用到这3种构造方式。但暴露的构造方法最终都会调用
public Handler(Callback callback, boolean async)或者(Looper looper, Callback callback, boolean async)三个参数的方法,其中callback参数可以为null,而looper的参数不能为null;
区别在于用的是默认的Looper.myLopper()去获取一个Looper对象,还是我们自己创建的Looper对象,此方法到底有什么作用?以及什么时候需要我们自己创建Looper对象?
如果looper为null,将抛出异常信息“Can't create handler inside thread that has not called Looper.prepare()”,此处就会有疑问,为什么平常我们从子线程发送消息到主线程的时候,我也没有创建Looper对象,怎么没报异常。答案是,在ActivityThread主线程中,系统其实已经帮我们调用了
此处需要注意的是构造方法中有一句mQueue = mLooper.mQueue;告诉我们,Handler中的MessageQueue实际调用的是Looper当中的MessageQueue
那么Looper到底是什么。以及他的作用是什么。继续分析。
public void Handler(){
this(null, false);
};
public void Handler(Callback callback){
this(callback,false)
};
public void Handler(Looper looper){
this(looper,null,false)
};
public void Handler(boolean){};
public Handler(Callback callback, boolean async) {
...
...
//主要行,通过Looper.myLooper();
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
//使用{@link Looper}作为当前线程,并设置处理程序是否应该是异步的。
public Handler(Looper looper, Callback callback, boolean async) {
mLooper = looper;
mQueue = looper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
Looper是什么
- 用于为线程运行消息循环的一个类
- 如果需要创建一个,需要在轮训消息循环的线程中用prepare()方法创建一个,然后调用Looper.loop()方法处理消息,直到停止轮训操作。
Looper.prepare()方法:
- 通过sThreadLocal.set(new Looper(quitAllowed)),会调用Looper的构造方法创建一个looper对象,并添加到Threadlocal中。
public static void prepare() {
prepare(true);
}
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));
}
- 而在Looper的构造方法中(这是一个私有的构造方法),创建了一个MessageQueue消息队列,并将mThread指定为当前创建此Looper的线程。
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
Looper.myLooper()方法
- 此方法的作用是从threadlocal中获取一个Looper对象
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
Looper.loop()方法:
- 可以看到此方法中, 通过取出一个Looper对象me,通过looper对象拿到消息队列queue,再遍历队列,取出消息msg,通过与msg关联的target,也就是handler对象,最终调用disaptchMessage方法。
...
final Looper me = myLooper();
...
final MessageQueue queue = me.mQueue;
...
Message msg = queue.next();
..
msg.target.dispatchMessage(msg);
完整代码如下:
public static void loop() {
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue;
// Make sure the identity of this thread is that of the local process,
// and keep track of what that identity token actually is.
Binder.clearCallingIdentity();
final long ident = Binder.clearCallingIdentity();
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
// This must be in a local variable, in case a UI event sets the logger
final Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
}
final long traceTag = me.mTraceTag;
if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
}
try {
msg.target.dispatchMessage(msg);
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
if (logging != null) {
logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
}
// Make sure that during the course of dispatching the
// identity of the thread wasn't corrupted.
final long newIdent = Binder.clearCallingIdentity();
if (ident != newIdent) {
Log.wtf(TAG, "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);
}
msg.recycleUnchecked();
}
}
handler的dispathchMessage(Message msg)方法:
- 如果构造handler时callback参数不为null,会调用callback接口里面的方法,返回值为false的情况下,还会调用handler自身的handleMessage(msg)方法。如果msg的callback不为空,则只调用msg的callback.
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
关于Message对象的创建发送问题
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
遗留问题:延迟发送收到消息是怎么实现的
例子
- 测试在子线程中创建handler,就需要Looper.prepare(),以及最末调用looper.loop方法;不加会报错。
- 通过使用子线程的handler,在主线程以及子线程中每隔1秒发送消息,子线程中的handler能够收到。
- 至于在主线程中创建handler,以及在子线程中或主线程中发送消息的情况是,我们经常使用的。就不写例子了,强调的地方是这些情况不需要looper.prepare以及looper.loop方法了,系统已经加上这两句。
public class MainActivity extends AppCompatActivity {
private static final String TAG="TestHandler";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void onClick(View view) {
SubHandlerThread subHandlerThread=new SubHandlerThread();
subHandlerThread.start();
//主线程中用子线程的handler每隔一秒发送消息。
while (true){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
if(subHandlerThread.handler!=null){
Message message=new Message();
message.obj=Thread.currentThread().getName();
subHandlerThread.handler.sendMessageDelayed(message,1000);
}
}
}
//在子线程中创建Handler
public class SubHandlerThread extends Thread {
public Handler handler;
@Override
public void run() {
setName("SubHandlerThread");
Looper.prepare();
handler = new Handler(new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
Log.d(TAG, "handleMessage in Callback: " + msg.obj);
return false;
}
}) {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Log.d(TAG, "handleMessage: Received: " + msg.obj);
}
};
//方式一
//Runnable runnable=new RepeatMessage(handler);
//runnable.run();
//方式二
Thread subThread = new Thread(new RepeatMessage(handler), "sub thread");
subThread.start();
Looper.loop();
}
}
//子线程中用子线程的handler每隔一秒发送消息到handler.
public class RepeatMessage implements Runnable{
private Handler handler;
public RepeatMessage(Handler h){
this.handler=h;
}
@Override
public void run() {
//让子线程每隔一秒发送一个消息的方式一
// while (true){
// try {
// Thread.sleep(1000);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
// if(handler!=null) {
// Message msg = new Message();
// handler.sendMessage(msg);
// Log.d(TAG, "run: "+count);
// }
// }
//让子线程每隔一秒发送消息的方式二
if(handler!=null) {
Message msg = new Message();
msg.obj=Thread.currentThread().getName();
handler.sendMessage(msg);
handler.postDelayed(RepeatMessage.this,1000);
}
}
}
}
总结
- handler既可以在子线程创建,也可以在主线程创建。
- 在创建handler之前需要调用Looper.prepare()方法准备一个looper对象。在主线程不需要,系统已经创建好了。
- 在发送消息后面调用looper.loop方法。主线程不需要,系统已调用。
- handler中的messagequeue是拿的looper中的messagequeue。这就解释了为什么需要先创建looper对象。
- looper.prepare()方法调用looper构造方法,构造方法中创建的messagequeue.
- handler发送的消息会加入messagequeue,looper.loop方法会轮询messagequeue,取得一个message,该message的target去处理消息
- 一个message的target就是一个handler。
8.发送Runnable对象时,都会将Runnable封装成一个Message
9.发送消息最终都会走enqueueMessage方法。