您的位置:首页 > 移动开发 > Android开发

AndroidHandler源码级分析及实现

2017-05-29 23:55 381 查看

AndroidHandler源码级分析及实现

1.android handler 概述

百度百科:Handler主要用于异步消息的处理:当发出一个消息之后,首先进入一个消息队列,发送消息的函数即刻返回,而另外一个部分在消息队列中逐一将消息取出,然后对消息进行处理,也就是发送消息和接收消息不是同步的处理。 这种机制通常用来处理相对耗时比较长的操作。

handler,looper,message三者都是与android异步消息处理机制相关的概念。当调用handler.sendMessage()时,会调用queue.enqueueMessage()消息入队。然后出队时Looper消息轮循器会调用looper.loop(),然后MessageQueue.next(),再然后在回调message.dispatherMessage(),最后再调handlerMessage(),就完成了出队。

2.源码详细解析

先上一张图,有助于大家理解,下面我会刨析这张图:



第一步:handler.sendMessage()发送消息

不管你是调用哪个发送消息的方法,最终都会调用下面的方法,看到了return语句没有,是不是调用了queue.enqueueMessage(),这样就完成了消息入队,至于queue是什么,其实queue就是MessageQueue,可以理解为消息的仓库,简称消息队列。

private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}


第二步:Lopper轮询器会轮询消息

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));
}
ThreadLocal防止多线程脏读问题
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);//消息转发再由handlerMessage()处理
} 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();
}
}
loop->MessageQueue.next()->message.dispatherMessage()
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
可以看出message.dispatherMessage()->handlerMessage()

handler大致结构:

Handler类有:Looper looper;MessageQueue mQueue;

Looper类有:MessageQueue mQueue;prepare()->sThreadLocal.set();loop()->myLooper()->sThreadLocal.get()

MessageQueue类有:enqueueMessage()消息入队/生产者;next()消息出队/消费者

Message类有:Handler target;int what;Object obj;

下面将根据这个类结构去自定义handler

3.自定义handler

Handler:

public class Handler {
private Looper mLooper;
private MessageQueue mQueue;
public Handler(){
mLooper=Looper.myLooper();
mQueue=mLooper.mQueue;
}

/**
* 发送消息
* @param msg
*/
public void sendMessage(Message msg){
msg.target=this;
mQueue.enqueueMessage(msg);
}

/**
* 转发消息
* @param msg
*/
public void dispatherMessage(Message msg){
handlerMessage(msg);
}

/**
* 处理消息
* @param msg
*/
public void handlerMessage(Message msg){

}
}


Looper轮询器

/**
* 一个线程只有一个lopper对象,prepare不为空抛异常
*/
public class Looper {
//ThreadLocal 防止脏读
private static ThreadLocal<Looper>mThreadLocal=new ThreadLocal<Looper>();
public MessageQueue mQueue;
public Looper(){
this.mQueue=new MessageQueue();
}
/**
*
* @return 返回当前线程绑定的lopper对象
*/
public static Looper myLooper(){
return mThreadLocal.get();
}

public static void prepare(){
Looper lopper=myLooper();
if(lopper!=null){
throw new RuntimeException("only one looper may be created per thread");
}
mThreadLocal.set(new Looper());
}

/**
* 轮询器轮询消息队列
*/

public static void loop(){
Looper me=myLooper();
if(me==null){
throw new RuntimeException("No Looper:Looper.prepare()wasn't called on this thread.");
}
MessageQueue mQueue=me.mQueue;
for(;;){
Message msg=mQueue.next();
if(msg==null){
continue;
}
//转发
msg.target.dispatherMessage(msg);
}
}
}


消息队列MessageQueue,对于这个类我多做一点解释,防止不了解线程间通信的读者看不懂。

Object类有三个方法值得注意:wait(),notify(),notifyAll().这三个方法必须有同步监视器对象来调用

wait():导致当前线程等待,直到其它线程调用该同步监视器的notify()或者notifyAll()来唤醒该线程。

notify():唤醒在此同步监视器等待的单个线程,选择是任意性的。

notifyAll():唤醒在此同步监视器等待的所有线程。

传统的线程通信使用Synchronized修饰的同步方法,因为该类的默认实例(this)就是同步监视器,所以可以在同步方法中调用这三个方法。

传统的线程通信使用Synchronized修饰的同步代码块,同步监视器是Synchronized后括号里的对象,所以必须使用该对象调用这三个方法。

这是传统的使用Synchronized关键字来保证同步,如果不喜欢用这个,可以试试Lock对象,本程序用的就是这个对象。如果用的是Lock对象,程序中就不存在隐式的同步监视器,也就不能使用wait(),notify(),notifyAll()。所以java就提供了Conditionl类来保持协调。提供的三个方法await(),signal(),signalAll()与上面三个方法类似,不多累赘。

/**
* //不加锁,供不应求 ,供大于求
* Created by Administrator on 2017/5/29.
*/

public class MessageQueue {

Message[]items;//消息数组
int putIndex;//入队索引
int takeIndex;//出队索引
int count=0;//消息个数
Lock lock;//添加锁 阻塞队列 java高并发编程
Condition notEmpty;//消费者
Condition notFull;//生产者
public MessageQueue(){
this.items=new Message[50];
this.lock=new ReentrantLock();
this.notEmpty=lock.newCondition();
this.notFull=lock.newCondition();
}
/**
* 消息入队(生产者) sendMessage()里面调用是子线程
* @param msg
*/
public void enqueueMessage(Mes
c079
sage msg){
try {
lock.lock();//加锁
if (count == items.length) {
//阻塞 已经满了,不能再生产了
notFull.await();
}
items[putIndex] = msg;
putIndex = (++putIndex == items.length) ? 0 : putIndex;
//队列不为空,通知消费者线程可以消费
notEmpty.signalAll();//防止多个子线程 没有唤醒
}catch (InterruptedException e){
e.printStackTrace();
}finally {
lock.unlock();
}

count++;
}

/**
* 消息出队(消费者)  looper调用 ,是主线程
* @r  */
public Message next(){
Message msg=null;
try {
lock.lock();
//没有产品了,不能消费
while(count==0){
notEmpty.await();
}
msg = items[takeIndex];
items[takeIndex] = null;//出队后置空
takeIndex = (++takeIndex == items.length) ? 0 : takeIndex;
count--;
notFull.signalAll();//防止多个子线程 没有唤醒
}catch (InterruptedException e){
e.printStackTrace();
}finally {
lock.unlock();
}
return msg;
}
}
Message

public class Message {
Handler target;//默认修饰符
public int what;
public Object obj;

@Override
public String toString() {
return obj.toString();
}
}
TestHandler测试类(消息机制不光光是更新ui,更准确的说是通信,所以下面的测试代码我故意放在了子线程。for循环开启10个子线程测试我写的handler是否是线程安全的,测试结果显示是线程安全的,因为消息队列加锁了)

public class TestHandler {
public static void main(String[]args){
//消息机制不光光是更新ui的,最准确地来说是通信的,因为我可以放在ui线程执行也可以放在子线程
new Thread(){
@Override
public void run() {
Looper.prepare();
final Handler handler=new Handler(){
@Override
public void handlerMessage(Message msg) {
System.out.println(Thread.currentThread().getName() + "    receiver:"+msg.toString());
}
};
for(int i=0;i<10;i++) {//多线程跑测试自己的handler是不是线程安全的,结果发现是的
new Thread() {
@Override
public void run() {
while (true) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Message msg = new Message();
msg.what = 1;
//多线程一起跑randomUUID要加个锁
synchronized (UUID.class){
msg.obj = UUID.randomUUID().toString();
}

System.out.println(Thread.currentThread().getName() + "    send:" + msg.toString() + "    ");
handler.sendMessage(msg);
}
}
}.start();
}
Looper.loop();
}
}.start();

}
}
测试结果贴图:



Thread-0就是接受的子线程,就是消费者

Thread-1到Thread-10就是10个子线程,不停地发消息,10个生产者

从上面你可以看出1-10生产者生产出来的msg在0这个消费者总是能接受到消息

测试通过,万事大吉!

4.总结

学习是一个漫长的过程,彼此共勉!加油!!!

ps:上述如有不对的地方,欢迎指出,一起交流!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息