Android Handler机制再解读

一、handler机制是什么?

    handler是Android用于线程间通信的一种机制

主线程运行起来,就会初始化一个Looper对象,Looper对象里有一个MessageQueue对象,
在主线程中new一个Handler对象,子线程中可以调用到主线程的handler对象。因为它是一个成员变量。
主线程new Handler(),就已经获取到了当前线程的Looper对象和MessageQueue对象。
在子线程中通过Message.obtain()方法创建Message对象,通过handler将message对象发(sendMessage()方法)到主线程中的MessageQueue中,
sendMessage()方法会调用到enqueueMessage(),在enqueueMessage方法中,通过msg.target = this; 把handler保存到了Message里面,
最后执行到了消息队列的queue.enqueueMessage方法中去。消息队列的enqueueMessage方法主要是在消息队列中找一个合适的位置,将消息插入到消息队列中
主线程的Looper轮循器在MessageQueue中轮训消息,如果拿到消息了,就调用Looper的loop()方法,Looper的loop方法里
有个无限循环,将消息队列MessageQueue中的消息Message取出,交给msg的target也就是handler,调用handler的dispatchMessage(msg)方法处理。

Looper类:
    final MessageQueue mQueue;
    private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
    }

Message类:
	public int what; //消息的标记位
	public int arg1;
	public int arg2; //存储一个int类型的数据
	public Object obj; //存储一个对象类型的数据
	Handler target;
	Runnable callback;
	Message next;
	public static final Object sPoolSync = new Object();
    	private static Message sPool; //消息池里的第一条消息,其实是一个存储了消息队列的一个链表
    	private static int sPoolSize = 0;
    	private static final int MAX_POOL_SIZE = 50;//消息池的默认最大数量是50

    //从消息池中返回一个消息实例
    public static Message obtain() {
        synchronized (sPoolSync) {
            if (sPool != null) {
                Message m = sPool;
                sPool = m.next;
                m.next = null;
                m.flags = 0; // clear in-use flag
                sPoolSize--;
                return m;
            }
        }
        return new Message();
    }


Handler类:
    public Handler(@Nullable Callback callback, boolean async) {
        mLooper = Looper.myLooper(); //new handler的时候,就已经获取到了当前线程的Looper对象和MessageQueue对象
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread " + Thread.currentThread()
                        + " that has not called Looper.prepare()");
        }
        mQueue = mLooper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }
	/**
     * Subclasses must implement this to receive messages.
     * 子类必须重写这个方法来接收消息
     */
    public void handleMessage(@NonNull Message msg) {
    }

    /**
     * Handle system messages here.
     * 分发消息
     */
    public void dispatchMessage(@NonNull Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }

    /**
     * Pushes a message onto the end of the message queue after all pending messages
     * before the current time. It will be received in {@link #handleMessage},
     * in the thread attached to this handler.
     *  在当前时间之前所有挂起的消息之后将消息推到消息队列的末尾。它将在附加到该handler的线程中的{@link #handleMessage}中接收。
     * @return Returns true if the message was successfully placed in to the 
     *         message queue.  Returns false on failure, usually because the
     *         looper processing the message queue is exiting.
     */
    public final boolean sendMessage(@NonNull Message msg) {
        return sendMessageDelayed(msg, 0);
    }
    sendMessageDelayed会调用到下面的方法中去:
    private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,long uptimeMillis) {
        msg.target = this; //handler发消息的时候,就把handler保存到了Message里面了
        msg.workSourceUid = ThreadLocalWorkSource.getUid();

        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);//handler发消息的时候,把message保存到MessageQueue中
    }
	最后执行到了消息队列的queue.enqueueMessage方法中去。

MessageQueue类:
    //在消息队列中找一个合适的位置,将消息插入到消息队列中
    boolean enqueueMessage(Message msg, long when) {
        synchronized (this) {
            msg.markInUse();
            msg.when = when;
            Message p = mMessages;//mMessages是消息池里的第一条消息
            boolean needWake;
            //如果消息队列中没有消息,或者当前消息的时间比队列中的消息的时间小,
            //则让当前消息成为队列中的第一条消息
            if (p == null || when == 0 || when < p.when) {
                // New head, wake up the event queue if blocked. 新头,如果被阻止,唤醒事件队列。
                msg.next = p;
                mMessages = msg;
                needWake = mBlocked;
            } else {
                // Inserted within the middle of the queue.  Usually we don't have to wake
                // up the event queue unless there is a barrier at the head of the queue
                // and the message is the earliest asynchronous message in the queue.
	// 插入到队列中间。通常我们不需要唤醒事件队列,除非在队列的顶部有一个屏障,
	// 并且消息是队列中最早的异步消息。
                needWake = mBlocked && p.target == null && msg.isAsynchronous();
                Message prev;
                for (;;) {
                    prev = p;
                    p = p.next;
                    if (p == null || when < p.when) {
                        break;
                    }
                    if (needWake && p.isAsynchronous()) {
                        needWake = false;
                    }
                }
                msg.next = p; // invariant: p == prev.next
                prev.next = msg;
            }

            // We can assume mPtr != 0 because mQuitting is false.
            if (needWake) {
                nativeWake(mPtr);
            }
        }
        return true;
    }
标题

二、怎么从子线程发送消息到主线程?

//在主线程中初始化Handler
  private Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
        //在此处处理消息
        }
    };


 Thread thread = new Thread(){
            @Override
            public void run() {
                super.run();
                //在子线程中发送消息
                handler.sendEmptyMessage(0);
            }
        };
  thread.start();

三、怎么从主线程发送消息到子线程?(虽然使用的少)

Thread thread = new Thread(){
            @Override
            public void run() {
                super.run();
                //初始化Looper,一定要写在Handler初始化之前
                Looper.prepare();
                //在子线程内部初始化handler即可,发送消息的代码可在主线程任意地方发送
                handler=new Handler(){
                    @Override
                    public void handleMessage(Message msg) {
                        super.handleMessage(msg);
                      //所有的事情处理完成后要退出looper,即终止Looper循环
                        //这两个方法都可以,有关这两个方法的区别自行寻找答案
                        handler.getLooper().quit();
                        handler.getLooper().quitSafely();
                    }
                };
              
                //启动Looper循环,否则Handler无法收到消息
                Looper.loop();
            }
        };
        thread.start();
    //在主线程中发送消息
    handler.sendMessage();

四、handler的执行逻辑,即handleMessage()方法的执行逻辑,到底是在子线程还是主线程?

    答案:handler在哪个线程中发送消息,就在那个线程中执行handleMessage。并不是在handler初始化的线程中执行的。可以从下面分析中找的解释。当我们调用handler.senMessage()方法的时候,最终的结果只是将这个消息插入到了消息队列中,在Looper的loop死循环中(循环的目的是从MessageQueue中取出消息,循环跳出的条件是MessageQueue.next()方法返回了null),通过调用MessageQueue.next()方法取出消息,然后调用message.target对象的dispatchMessage()方法分发消息,而message.target对象也就是上面handler在发送消息时,调用到了enqueMessage方法,在该方法中第一行就对message.target进行了赋值。Looper取出消息后,调用了发送消息的Handler的dispatchMessage()方法,并且将message本身作为参数传了回去。到此时,代码的执行逻辑又回到了Handler中

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

五、一个线程可以有几个Handler?几个Looper?几个MessageQueue?

    答案:一个线程中handler对象不限制,但是只可以有一个looper(通过调用Looper的prepare()方法来初始化一个Looper对象),也只能有一个MessageQueue。因为MessageQueue是随着Looper的初始化而初始化的,而且MessageQueue的构造方法是default的,也就是说,只有跟MessageQueue同一个包下才可以实例化MessageQueue,换句话说,我们用户是无法直接new一个MessageQueue对象出来的。而因为Looper在一个线程中只能有一个,从而导致MessageQueue也只能有一个

Only one Looper may be created per thread

六、在子线程中new一个handler的时候,必须先调用Looper的prepare方法。最后还要调用Looper的loop方法来循环执行。

七、Looper的Loop()方法到底是不是阻塞操作?如果是?主线程的Looper为什么没有阻塞主线程?如果不是,那你怎么解释Looper.loop()方法?

    答案:Activity 的生命周期都有对应的 case 条件了,ActivityThread 有个 getHandler 方法,得到这个 handler 就可以发送消息,然后 loop 里就分发消息,然后就发给 handler, 然后就执行到 H(Handler )里的对应代码。所以这些代码就不会卡死~,有消息过来就能执行。简单的来说:ActivityThread的main方法主要就是做消息循环,一旦退出消息循环,那么你的程序也就可以退出了。

参考文档:

1、https://www.jianshu.com/p/f7cabfe19720

2、https://www.jianshu.com/p/595355e6126d

3、第七个问题:https://www.cnblogs.com/chenxibobo/p/9640472.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值