Handler机制原理

1.应用场景(什么情况下用到Handler机制)

倒计时(用Handler可以,并不是Handler机制)

网络请求(异步):

子线程获取数据交给主线程更新UI的时候,(子线程不能更新UI,如果更新,报错)

主线程不能直接网络请求

在后台执行耗时操作需要Service,

在Service中进行耗时操作,如果是HttpURLConnection则不行,需要自己new一个子线程,Retrofit和OKHttp可以,因为这两个里面自带异步,

同步和异步

1.2后台下载文件Service需要开启子线程进行网络请求下载文件,提示用户下载成功的时候,不能在子线程里面直接Toast,Handler发送消息给主线程直接在Service)

3.BroadcastReceiver(广播) 也是默认运行在主线程

Handler中重要的几个类:

Handler:

句柄 作用1:将子线程中的Message消息发送给主线程

  作用2:可以将主线程Message消息发送到子线程

  作用3:处理Message消息

Message:

消息对象,存储数据    

Message msg= new  Message();  每次需要的时候就带创建对象,浪费资源

Message msg =handler.obtainMessage(); 消息池可以复用Message对象(比较节省资源)

MessageQueue:

(Activity任务栈,先进后出原则,)

先进先出原则

每个线程都有一个MessageQueue对象,主线程在创建的时候会默认创建一个MessageQueue对象,      {子线程通过new的方式}  同时与之对应的还有个looper对象

Looper:

每一个线程都有一个Looper对象

作用:将MessageQueue里面的消息轮询出去交给Handler处理Looper.loop()死循环,会不停的从MessageQueue里面取消息,有消息就取出,没消息MessageQueue消息队列就处于阻塞状态,loop()就跳出死循环.

状态: 子线程获取Looper对象的话需要通过


Handler它是Android线程间通信工具类。

一般用于子线程向主线程发送消息,将子线程中执行结果通知主线程,从而在主线程中执行UI更新操作。

源码角度理解

Handler负责发送(sendMessage)和处理消息(handleMessage)

1)Message:消息载体,包含消息id(what)、消息处理对象(obj)、Runnable接口等。Handler发送一条消息后,会将该消息加入到MessageQueue统一消息处理队列中。

2)MessageQueue:消息队列。用来存放Handler发送的消息的队列,单链表实现

3)Looper:消息泵,通过Looper.loop( )创建一个死循环,不断地从MessageQueue中抽取Message,Message通过绑定的内部target(handler类型),msg.target.dispatchMessage(msg)将该消息传给对应的Handler接收。在dispatchMessage方法内调用handleCallback或handleMessage方法

ThreadLocal理解

创建Handler对象时,需要先为这个Handler创建Looper.prepara( )新建一个looper对象。一个线程中只会有一个looper。因为looper使用ThreadLocal.set方法。在set方法中,会对应着当前Thread,将Looper存储在其成员变量ThreadLocalMap中。其中key是ThreadLocal,value是looper。因此looper-threadLocal-Thread是一一对应关系。

实际上ThreadLocal的值是放入了当前线程的一个ThreadLocalMap实例中,所以只能在本线程中访问,其他线程无法访问。

对象存放在哪里

在Java中,栈内存归属于单个线程,每个线程都会有一个栈内存,其存储的变量只能在其所属线程中可见,即栈内存可以理解成线程的私有内存。而堆内存中的对象对所有线程可见。堆内存中的对象可以被所有线程访问。

Handler发送和处理消息过程分析

Handler发送消息:Handler.sendMessage(Message message)

Handler处理信息:

new  Handler(){

        // 通过复写handlerMessage()从而确定更新UI的操作

        @Override

        public void handleMessage(Message msg) {

                ...// 需执行的UI操作

            }

    };

sendMessage方法将message 入队messageQueue(单链表实现,接着说数据结构链表)在ActivityThread中会调用Looper.prepareMainLooper()生成looper,looper中会创建MessageQueue 。Looper.loop( )中有个死循环,不断从messageQueue中取message。

public static void main(String[] args) {

    Looper.prepareMainLooper();

    long startSeq = 0;

    if (args != null) {

        for (int i = args.length - 1; i >= 0; --i) {

            if (args[i] != null && args[i].startsWith(PROC_START_SEQ_IDENT)) {

                startSeq = Long.parseLong(

                        args[i].substring(PROC_START_SEQ_IDENT.length()));

            }

        }

    }

    ActivityThread thread = new ActivityThread();

    thread.attach(false, startSeq);


    if (sMainThreadHandler == null) {

        sMainThreadHandler = thread.getHandler();

    }

    Looper.loop();

    throw new RuntimeException("Main thread loop unexpectedly exited");

}

Looper类

private Looper(boolean quitAllowed) {

    mQueue = new MessageQueue(quitAllowed);

    mThread = Thread.currentThread();

}


public static void loop() {


        ...// 仅贴出关键代码


        // 1. 获取当前Looper的消息队列

            final Looper me = myLooper();         

            final MessageQueue queue = me.mQueue;

            for (;;) {  

            Message msg = queue.next();

            if (msg == null) {

                return;

            }

            // next():取出消息队列里的消息

            // 若取出的消息为空,则线程阻塞


            // 2.2 派发消息到对应的Handler

            msg.target.dispatchMessage(msg);

            // 把消息Message派发给消息对象msg的target属性

            // target属性实际是1个handler对象

        // 3. 释放消息占据的资源

        msg.recycle();

        }

}

Handler中的dispatchMessage方法

public void dispatchMessage(Message msg) {

    if (msg.callback != null) {

        handleCallback(msg);

    } else {

        if (mCallback != null) {

            if (mCallback.handleMessage(msg)) {

                return;

            }

        }

        handleMessage(msg);

    }

}





Handler原理源码分析


/**

Handler:发送接收处理对象

Looper: 每一个线程只有一个looper.它是线程持有的looper中有一个Looper.loop()方法去读取MessageQueue中的消息,读出来之后会交给Handler来进行消息的处理

Message:是Handler接收和处理的对象,

MessageQueue:是用对应线程的Looper来创建和管理的

**/


Handler负责发送(sendMessage)和处理消息(handleMessage)

Message:消息载体,包含消息id(what)、消息处理对象(obj)、Runnable接口等。Handler发送一条消息后,会将该消息加入到MessageQueue统一消息处理队列中。

MessageQueue:消息队列。用来存放Handler发送的消息的队列,单链表实现

Looper:消息泵,通过Looper.loop( )创建一个死循环,不断地从MessageQueue中抽取Message,Message通过绑定的内部target(handler类型),msg.target.dispatchMessage(msg)将该消息传给对应的Handler接收。在dispatchMessage方法内调用handleCallback或handleMessage方法



原理流程:

首先子线程获取数据之后会通过Message.obtain()封装成Message对象,然后主线程创建好的Handler会将Message发送到主线程的MessageQueue中,在创建Handler的时候内部构造还会创建一个Looper对象,创建Looper对象的同时又会创建一个MessageQueue队列这个对象,Looper会通过Looper.Loop()方法会不断的轮询MessageQueue中的Message交给Handler处理


源码分析:

Handler源码


在创建Handler的时候,它构造内部会通过Looper.mylooper()创建一个Looper对象,除此之外,还会通过looper创建一个MessageQueue对象然后赋值给全局的MessageQueue对象,这样Handler和Looper就共用一个MessageQueue,这样这三者也就捆绑在一起了(如上图)


Handler源码


HandLer在发送消息的时候,不管是通过sendEmptyMessage()还是通过sendEmptyMessageDelayed()发送消息,最后消息都会走到enqueueMessage()方法中,这个enqueueMessage()方法其实就是将Handler发送的消息添加到MessageQueue消息队列中(如上图)



MessageQueue源码


而这个MessageQueue中主要包含,插入,读取和删除操作,在MessageQueue中有个enqueueMessage()方法,这个方法就是向MessageQueue中插入消息,而MessageQueue中会通过个next()方法获取下个Message,会被Looper.Loop()方法不停的取出Message对象,MessageQueue底层其实是通过单链表的数据结构来维护Message对象列表的(如上图)



Looper源码



public static void loop() {


        ...// 仅贴出关键代码


        // 1. 获取当前Looper的消息队列

            final Looper me = myLooper();         

            final MessageQueue queue = me.mQueue;

            for (;;) {  

            Message msg = queue.next();

            if (msg == null) {

                return;

            }

            msg.target.dispatchMessage(msg);

        msg.recycle();

        }

}


Handler源码中的dispathMessage()和HandleMessage()


MessageQueue是通过当前线程的Looper对象来管理和创建的,在Looper的构造中会创建个MessageQueue对象(如上图Looper源码),另外Looper中通过Prerare()方法来创建当前线程的Looper对象,在prepare()方法内部其实是通过ThreadLocal来保存和获取这个Looper对象的,ThreadLocal 不是 Thread,它是一个线程内部的数据存储类,通过它可以在指定的线程中存储数据,对数据存储后,只有在线程中才可以获取到存储的数据,对于其他线程来说是无法获取到数据。也就是说每个 Thread内可以通过ThreadLocal来创建变量的实例副本,且该副本只能由当前 Thread 可以使用,所以Threadlocal可以确保每个线程有唯一的一个Looper对象,Looper类中还有个loop()方法,其实内部是个死循环,在死循环内部通过queue.next()不停的从MessageQueue中轮询消息,如果没消息的话MessageQueue就处于阻塞状态,但是对当前主线程没影响,轮询出来消息之后会将Message交给Handler中的dispatchMessage()来处理,最后把Message交给在dispatchMessage()中的HandleMessage来处理。

你可能感兴趣的:(Handler机制原理)