美文网首页
handler源码分析

handler源码分析

作者: 人心与太阳我不敢直视 | 来源:发表于2017-05-03 10:59 被阅读0次

    版本不同源码不同;handler的作用是线程之间的通信,不仅仅是更新UI;

    消息的入队:Handler.sendMessage->queue.euqueueMessage通过底层c++native层来实现的

    出队:Looper.loop->(MessageQueue) queuq.next

    MessageQueue方法里有一个next方法有一个for循环,循环里面去不断拿消息(message),然后再返回消息

    Looper轮循器里面有一个loop方法会不断的调用queue.next方法,也是在死循环里面

    取出消息之后,再去转发(Message msg=queue,next();在try,catch里面msg.target(Handler).dispatchMessage(msg));然后调用handleMessage();

    handler发送一个消息会加到消息队列里面,然后Looper不断的从消息队列里面取出消息,又去调用handler的distchMessage方法传递消息,distchMessage又调用handleMessage()方法并传入消息;

    Looper轮循器总是按照先进先出的原则取出我们的消息

    在子线程发送handler消息,结果在主线程接收到的原理:因为Looper对象是在主线程调用的;      为什么handler发送消息要经过一圈再自己接收?如果handler发送消息不经过target可能需要再写一个类(可能是抽象类);

    loop方法里有一个死循环为什么在ActivityTreader里面调用不卡线程?因为loop是最后一个执行的,前面的应用创建都启动完成了,

    Handler里面有一个mLooper=Looper.myLooper(); mQueue=mLooper.mQueue;

    loop里面会调用myLooper方法里面有一个sThreadLocal.get();返回的是Looper对象

    在prepare方法里面sThreadLocal.set(new Looper(quitAllowed)); set里面创建了一个Looper对象

    存入Looper对象->prepare->sThreadLocal.set,获取Looper对象->loop->myLooper->sThreadLocal.get

    sThreadLocal是保证数据的隔离的,线程和线程之间数据不会影响,是一个map结构通过key和value来保存数据,A线程set进去的数据,通过get获取的是A线程的数据;会有多个线程来操作ThreadLocal,每个线程都有自己的Looper对象,

    ActivityThread启动的时候回调用main方法,在main方法里会调用prepare方法创建Looper对象;在我们启动应用程序的时候就会执行Looper.loop();方法里面有一个for循环会不断的拿到消息队列里面的消息,looper里面有一个MessageQueue

    一个线程只能有一个Looper对象,在prepare方法里首先判断sThreadLocal中是否已经存在Looper了,如果还没有则创建一个新的Looper设置进去。这样也就完全解释了为什么我们要先调用Looper.prepare()方法,才能创建Handler对象。同时也可以看出每个线程中最多只会有一个Looper对象。

    调用Looper前一定要先执行prepare,如果不执行prepare方法(mLooper = Looper.myLooper();)loop方法里会获得一个空的Looper对象,然后在判断如果是空的就抛出一个异常,Looper里面有一个消息队列;

    myLooper方法里返回一个sThreadLocal.get();也就是获取到的Looper对象;

    主线程不需要手动的去调用Looper.prepare();因为Activity启动应用的时候,在ActivityThread里面有个main方法在里面已经通过Looper.prepareMainLooper();方法调用了,因为prepareMainLooper()方法里有一个prepare(false);然后就会调用有参的prepare方法(有两个prepare方法一个无参返回,一个有参有参的里面可以创建Looper对象);


    MessageQueue是一个消息队列,他可以把存入的消息以队列的形式进行排列,并提供入队和出队的方法。这个类是在Looper的构造函数中创建的,因此一个Looper也就对应了一个MessageQueue。

    - 在worker线程中,如果直接创建handler会抛出运行时异常-即通过查‘线程-value’映射表发现当前线程无looper对象。所以需要先调用Looper.prepare()方法。在prepare方法里,利用ThreadLocal对象为当前线程创建一个Looper(利用了一个Values类,即一个Map映射表,专为thread存储value,此处为当前thread存储一个looper对象)。然后继续创建handler,让handler内部的消息队列指向该looper的消息队列(这个很重要,让handler指向looper里的消息队列,即二者共享同一个消息队列,然后handler向这个消息队列发送消息,looper从这个消息队列获取消息)。然后looper循环消息队列即可。当获取到message消息,会找出message对象里的target,即原始发送handler,从而回调handler的handleMessage() 方法进行处理。

    1、Handler为什么能够实现不同线程的通信?核心点在哪?

    不同线程之间,每个线程拥有自己的Handler、消息队列和Looper。Handler是公共的,线程可以通过使用目标线程的Handler对象来发送消息,这个消息会自动发送到所属线程的消息队列中去,线程自带的Looper对象会不断循环从里面取出消息并把消息发送给Handler,回调自身Handler的handlerMessage方法,从而实现了消息的线程间传递。

    2、Handler的核心是一种事件激活式(类似传递一个中断)的还是主要是用于传递大量数据的?重点在Message的内容,偏向于数据传输还是事件传输。

    目前的理解,它所依赖的是消息队列,发送的自然是消息,即类似事件中断。

    它的简单逻辑就是如果当前MessageQueue中存在mMessages(即待处理消息),就将这个消息出队,然后让下一条消息成为mMessages,否则就进入一个阻塞状态,一直等到有新的消息入队。

    子线程中更新UI的方法:

    1、Handler的post方法;

    在post方法里返回一个发送消息的方法(也就是sendMessageDelayed(getPostMessage(r),0)),方法里面有一个getPostMessage()方法里面有一个Runnable对象参数,后面还有个延时时间参数默认为0;在getPostMessage()方法里面得到了一个Message对象,m.callback = r;Message对象调用callback,这个callback在Handler的dispathMessage()方法中做了个判断,如果Message的callback等于null才会去调用handleMessage()方法,否则就调用handleCallback()方法。

    也太简单了!竟然就是直接调用了一开始传入的Runnable对象的run()方法。

    2、View的post()方法

    原来就是调用了Handler中的post()方法,我相信已经没有什么必要再做解释了。

    3、Activity的runOnUiThread()方法

    如果当前的线程不等于UI线程(主线程),就去调用Handler的post()方法,否则就直接调用Runnable对象的run()方法。

    相关文章

      网友评论

          本文标题:handler源码分析

          本文链接:https://www.haomeiwen.com/subject/zheszttx.html