Android消息机制(Handler机制)

Android中使用Handle,Looper来实现线程通信:
重点关注以下几个类:Handler,Looper,Message,MessageQueue,Thread,ThreadLocal,ThreadLocalMap

从子线程传递信息到主线程通常我们是这么操作:

    //在主线程构建Handler对象
    private Handler mHandler=new Handler(){
        //重写处理Message方法
        @Override
        public void handleMessage(Message msg) {
            //在这里对msg携带的信息进行处理
        }
    };

     //创建子线程,在子线程处理逻辑,将result存放进Message中通过Handler发送出去
        new Thread(new Runnable() {
            @Override
            public void run() {
                Message message=new Message();
                //message.what(obj,arg1,arg2)
                mHandler.sendMessage(message);
            }
        });

简化来说就是Handler将Message从子线程发送到主线程的MessageQueue,主线程有个Looper调用其Loop方法循环不断的检查MessageQueue一旦发现Message就将其dispatch给Handler的handleMessage方法进行处理:

接下来我们逐步分析这一过程的实现逻辑:
首先在当前线程通过Looper.prepare();构造Looper对象。点进源码:

    public static void prepare() {
        prepare(true);
    }

    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));
    }

我们可以看到prepare方法内部new了一个Looper对象,并将其set给了ThreadLocal;这里我们先不管ThreadLocal;
再看看Looper的构造方法:

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

注意这里的MessageQueue是final的,并且获取了当前线程对象;

现在有Looper对象了,我们继续调用其Looper.loop(),让循环系统运行起来,我们查看此方法源码(注:源码查看均只包含少部分关键,推荐自行查看):

    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;
        //构建了一个死循环不停从MessageQueue中取出
        for (;;) {
            Message msg = queue.next(); // might block
            if (msg == null) {
                return;
            }
            msg.target.dispatchMessage(msg);
            msg.recycleUnchecked();
        }
    }

可以看见我们调用Looper的myLooper()方法获取了Looper对象,

    public static @Nullable Looper myLooper() {
        return sThreadLocal.get();
    }

又是ThreadLocal,虽然我们不知道这个类具体做什么用,但从前面的set一个Looper对象和这里的get方法,我们可以猜测这里获取的就是我们当初保存的Looper对象,简单可以先把ThreadLocal归结为一个Looper的存储类先;
下面继续看,用Looper对象获取了MessageQueue,然后启动了一个无限的for循环,从里面取出Message来。
接着调用msg.target.dispatchMessage(msg)对Message进行分发。这里的target就是Handler对象;(Handler怎么成为Message的target的呢?)其实当我们调用handler.sendMessage的时候,就进行了这一步处理。我们稍后再讲;
到这里为止Looper的循环系统就构建完毕了,接下来我们来创建消息的处理者,Handler对象;

首先查看Handler的构造函数,依旧是关键代码:

    public Handler(boolean async) {
        this(null, async);
    }
    public Handler(Handler.Callback callback, boolean async) {
        mLooper = Looper.myLooper();
        if (mLooper == null) {
            throw new RuntimeException(
                    "Can't create handler inside thread that has not called Looper.prepare()");
        }
        mQueue = mLooper.mQueue;
    }

源码里首先通过Looper.myLooper();来获取了Looper对象,如果Looper对象为null,那么程序将抛出异常,这就是为何我们首先第一步是通过Looper.prepare创建Looper对象。
我们点击myLooper方法:

    public static @Nullable Looper myLooper() {
        return sThreadLocal.get();
    }

可以看出也是通过ThreadLocal.get()来获取的Looper对象。同样我们注意到Handler内MessageQueue也是通过此获取到的Looper来获取的。在这时我们应当有意识的猜想或者说认为,通过ThreadLocal来存储获取的Looper有一定得唯一性。(暂时不细纠为什么)
下面看Handler.sendMessage():

    public final boolean sendMessage(Message msg) {
        return sendMessageDelayed(msg, 0);
    }
    public final boolean sendMessageDelayed(Message msg, long delayMillis)
    {
        if (delayMillis < 0) {
            delayMillis = 0;
        }
        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
    }
    public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
        MessageQueue queue = mQueue;
        return enqueueMessage(queue, msg, uptimeMillis);
    }
    private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        msg.target = this;
        return queue.enqueueMessage(msg, uptimeMillis);
    }

可以看出此方法最终是将Handler自己设置为Message的target,且将Message加入了MessageQueue中等待Looper.loop的调用,刚才也看到loop方法最终是通过Handler的dispathMessage来对Message进行分发的:所以我们接着看dispath方法:

    public void dispatchMessage(Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }

终于最终我们回到了我们自己重写的handleMessage方法中。。

总结一下:

  1. Looper内包含一个final的MessageQueue
  2. A线程构造Looper对象
  3. A线程Looper.loop()启动无线循环
  4. A线程通过Looper对象构造Handler对象
  5. 此时Handler已持有Looper和MessageQueue
  6. B线程创建Message对象,通过Handler.sendMessage()将Handler自身传递给Message的target,并且将Message加入Handler已持有的MessageQueue中
  7. 在无线循环的Loop里,当检测到MessageQueue中出现Message,就会调用此Message的target(Handler)
  8. 调用target的dispatchMessage,将Message交给target的handleMessage()处理
  9. 这样B线程的Message就传递到了A线程的Handler中进行处理

这里有人会问我们子线程与主线程通信过程中并没有调用过prepare()方法创建过Looper对象啊。其实是因为主线程默认已经为我们创建过了,不信你可以试试在子线程创建Handler对象前不创建Looper,根据前面的源码可以看出会出现异常:”Can’t create handler inside thread that has not called Looper.prepare()”);
主线程是通过prepareMainLooper来进行Looper的初始化的:

    public static void prepareMainLooper() {
        prepare(false);
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            sMainLooper = myLooper();
        }
    }

那么ThreadLocal到底是做什么用的呢?
简单的说ThreadLocal的使用是为了实现多个Thread中存在多个互不影响的变量。(在Android的消息传递机制里,这个变量就是Looper),也就是保证每个Thread的Looper都独立而互不影响,影响范围被限制在自身Thread内。

我们首先查看Looper源码:
可见Looper内定义了一个ThreadLocal的静态变量,且泛型指定为Looper

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

回到Looper.prepare(),Looper.myLooper(),这次我们查看 ThreadLocal的set,get方法,首先是set:

    public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }

    ThreadLocalMap getMap(Thread t) {
        return t.threadLocals;
    }

这里的T便是我们new出的Looper,首先获取了当前Thread,然后通过getMap()获取了当前线程的变量ThreadLocalMap,接着将Looper存进map中;
ThreadLocalMap是什么呢?
通过源码查看,可得知ThreadLocalMap是ThreadLocal的静态内部类,用于封装泛型信息(即此处的Looper);
接着查看get方法:

    public T get() {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null) {
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null)
                return (T)e.value;
        }
        return setInitialValue();
    }
    ThreadLocalMap getMap(Thread t) {
        return t.threadLocals;
    }

可以看出同样是先获取当前Thread,然后从Thread的变量ThreadLocalMap中通过get取出set进去的泛型值;
总结一下:通过ThreadLocal的get/set方法:Looper被它所处线程的ThreadLocalMap所保存了起来。即Looper使用和自己所处Thread进行了绑定;
这样一来便实现了,Thread拥有各自的Looper且互不影响。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值