Android消息机制、handler运行机制

一、android消息机制的概述
android的消息机制主要值Handler的消息运行机制,Handler的运行需要底层的MessageQueue和Looper的支撑。MessageQueue为消息队列,它内部存储了一组消息,以队列的形式对外提供插入和删除工作,它只提供存储功能,不处理消息;而Looper会以无限循环的形式去查找是否有新的消息,如果有就处理,没有就一直等待着,还有就是looper它运行在handler创建的线程中。
二、ThreadLocal介绍
为什么要介绍它了,因为我们获取looper的时候跟它有关。
介绍:ThreadLocal是一个线程内部的数据存储类,通过它可以获取在指定的线程中的存储数据,数据存储以后,只有在指定线程中可以获取到数据,也就是说在当前线程中存储的数据只有在当前线程中才能获取,其它线程无法获取到,文字不太好理解,举个例子吧:


先定义一个ThreadLocal对象,这里选择Boolean类型的

在代码中主线程设置为ture,在#1中设置值为false,在#2中不设置值,运行结果如下:



从上面日志中可以看出,虽然在不同线程中访问同一个ThreadLocal对象,但是他们通过ThreadLocal获取的值却是不一样的,每个线程的值都是单独的 :主线程设置为true,获取的值就为true,#1设置为false,获取的值就为false;#2中没有设置值,所以获取的值为null.
三、MessageQueue工作原理
MessageQueue主要包含两个操作:插入和读取,读取操作本身会伴随着删除操作,插入和读取对应的方法分别为enqueueMessage()和next()这俩个方法,enqueueMessage的源码如下:


这里主要就是框起来这里的赋值操作,在next()方法的时候会去判断mMessage这个全局变量是否为空,而mMessage它就是我们传进来的消息对象。
在看next()方法的源码:

next()方法是个无限循环的方法,如果消息队列中没有消息就堵塞,当有新消息来时会返回这条消息,并把这条消息制为空,也就是在消息队列中移除。
四、Looper的工作原理
Looper主要的功能是,它会不停地从MessageQueue中查看是否有新的消息,如果有新的消息就会立即处理,否则就一直堵塞在那里。先看它的构造方法:

在构造方法中,它会建立一个MessageQueue消息队列,然后把当前线程对象保存起来。
我们知道Handler工作需要Looper,如果没有会报错,我们也知道可以通过Looper.prepare()来为当前线程创建一个Looper,源码如下:

代码很简单,给ThreadLocal设置一个Looper();

创建Looper后可以通过Looper.loop()来开启消息循环,如下图:


Looper最重要的一个方法就Loop()方法,只有调用了Loop()方法以后,消息循环才正真的起作用,接下来详细的讲解一下,它的源码如下:

loop这个方法主要去循环消息队列中的消息,如果有的话就调用handler的dispatchMessage()方法。
下面来介绍loop几个主要的方法:
1.myLooper(),首先看源码:


这个很简单,就是获取我们初始化时设置进去的looper,只要记住它获取的是handler创建线程的Looper就行了。
获取Looper后就可以得到messageQueue了,因为我们初始化looper的时候就创建了一个,可以去看looper构造方法的代码就明白了。
获取messageQueue后就调用它的next()方法,前面有讲到它的源码它就是,如果有新的消息就返回,并把消息移除,如果没有消息就堵塞。
然后判断msg是否为空,如果为空的话就跳出循环,可以调用messageQueue的quit()方法让looper跳出循环:

msg.target.dispatchMessage(msg)这个方法是非常重要,它让消息从线程中进行了切换,因为msg.target其实就是一个handler:

当我们调用Handler的obtainMesage()方法时,它会调用message的obtain方法,并把自己传进去:

然后在message类中设置target的值:

所以从上面代码中看出,msg.target就是我们创建的handler,然后获取的looper也是跟handler运行在同一线程,所以他调用的就是我们创建的handler的dispatchMessage()方法:




从这个方法可以看出他判断了msg是否有回调方法,然后handler自己是否有设置回调方法,如果没有的话就调用handleMessage()方法。
五、Handler的工作原理
handler主要介绍一个enqueueMessage()方法,因为所有的发送消息的方法调用的都是这个方法:

从代码中发现它最后还是调用了messageQueue中的enqueueMessage()方法,而这个方法就是往消息队列中添加一条数据。
然后看一下handler的构造方法:



handler有七个构造方法,他们分别调用了这两个构造方法,一个是不传Looper一个是传递looper。

六、主线程的Looper创建
android的主线程就是ActivityThread,主线程的入口方法为main(),源码如下:

可以看到在主线程中系统会通过Looper.prepareMainLooper()方法创建Looper,并通过Looper.loop()来开始循环,所以在主线程中不用我们自己初始化Looper;
prepareMainLooper()源码:

----------------------------------------------------------------------------------------------------------------------------
下面我自己写了个handler消息机制的代码,只写了一下重要的代码,有很多的细节和判断没有涉及到,但是整个流程是没有问题的,还有因为是死循环可能会有点卡:
1.创建handler类:
public class Handler {

private MessageQueue queue;

public void handleMessage(Message msg) {

}

public void dispatchMessage(Message msg) {
//调用handleMessage
handleMessage(msg);
}

public final Message obtainMessage()
{
return Message.obtain(this);
}

public Handler(){
//在主线程会自动获取looper
Looper looper = Looper.myLooper();
queue = looper.queue;

}

public Handler(Looper looper){
queue = looper.queue;

}

public boolean sendMessage(Message msg){

return queue.enQuequMessage(msg,0);

}
}



2.创建Message类:

public class Message {

public Handler target;
public Object obj;
public int what;
public int arg1;
public Message next;
public int flags;
private static Message sPool;


public static Message obtain(){
if (sPool != null){

Message m = sPool;
sPool = m.next;
m.next = null;
m.flags = 0; // clear in-use flag
return m;
}

return new Message();

}

public static Message obtain(Handler h) {
Message m = obtain();
m.target = h;//在这里赋值handler

return m;
}

}


3.创建MessageQueue类
public class MessageQueue {

private Message mMessage;
private boolean mQuitting;


public boolean enQuequMessage(Message msg,long when){

if (msg.target == null){
//判断handler是否为空
throw new IllegalArgumentException("Message must have a target.");
}

Message p = mMessage;
if (p == null){
msg.next = p ;//这里设置为null
mMessage = msg;//把消息赋值给成员变量
}

return true;

}

public Message next(){
for (;;){
Message prevMsg = null;
Message msg = mMessage;
if (msg != null && msg.target == null){
//判断handler等于null
do {
prevMsg = msg;
msg = msg.next;//这里把他设置成了null,因为上面设置了值为null
}while (msg != null);
}
if (msg != null){
if (prevMsg != null) {
//把next设置成null
prevMsg.next = msg.next;
} else {
mMessage = msg.next;//把成员变量mMessage设置成null
}
msg.next = null;
return msg;
}

if (mQuitting){
return null;
  }

 }

}

/**
* 退出循环
* @param mQuitting
*/
public void quit(boolean mQuitting){
this.mQuitting = mQuitting;

   }

}


4.创建Looper类
public class Looper {


private static ThreadLocal<Looper> sThreadLocal = new ThreadLocal<>();


public MessageQueue queue;
// private Thread thread;

public Looper(boolean quitAllowed){
queue = new MessageQueue();
// thread = new Thread();
}
public static void prepare() {
prepare(true);
}

private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
//判断是否已经有了looper
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}

/**
* 从ThreadLocal中获取looper
* @return
*/
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
 }


public static void loop(){

Looper me = myLooper();//获取looper,这个looper跟handler在同一个线程
if (me == null) {
//判断是否为空
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
  }

MessageQueue queue = me.queue;
for (;;){
//进入死循环
Message msg = queue.next();//掉用next方法,如果没有消息的话会一直堵塞在这里

if (msg == null){
//当next()方法返回null的时候跳出循环
return;
  }
if (msg != null){
//调用handler的方法 主要的线程切换就在这里完成 因为这里looper是handler运行线程的looper
msg.target.dispatchMessage(msg);
   }

  }

}

public static Looper getMainLooper() {
prepare();
return myLooper();
  }

}


5.创建mainActivity测试


运行结果:


根据日志可以看出运行在不同的线程中,接收数据没有问题。

以下是我自己的总结出来的handler的运行流程:
1.looper.perpp();初始化Looper和消息队列 MessageQueue(在主线程中不需要手动操作)
2.Handler handler = new Handler();创建handler,获取looper, 获取消息队列MessageQueue的值 mLooper.mqueue
3.Message msg = handler.obtainMessage();获取消息对象,并把handler跟Message对象的target进行绑定
4.msg.obj = xxx;设置传递消息的值
5.调用handler.sendMessage(msg)方法
6.调用消息队列MessageQueue方法的enqueueMessage()方法添加消息到消息队列
7.调用looper.loop()方法(在主线中不需要手动操作)
8.loop方法里先获取looper
9.然后获取消息队列MessageQueue
10.然后调用消息队列的next()方法开始循环消息
11.如果有消息的话调用handler.dispatchMessage()方法
12.在dispatchMessage()方法中判断是否消息的回调和handler的回调方法如果没有就调用handleMessage()方法;


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值