Android开发Handler消息机制深入探究

提到Handler,大家不免会想到更新主界面或者延时操作。其实handler在安卓开发中扮演的主要角色就是随时更新主界面的。为什么要采用handler来更新主界面呢,这里又要谈到主线程的不安全原则。

我们知道一个应用启动时系统会为其创建一个进程,而每一Activity启动的时候又会形成一个线程,这个线程叫主线程。安卓的主线程是不安全的,因为从主线程中可以创建多个子线程来分配任务,一个activity的所有view都是唯一的,都有唯一的标识,如果在每个子线程中更新view,我们不能预知线程执行结果的先后顺序,也就无法预知什么时候才能更新view,所以造成结果就是view更新时的冲突问题。这也就是为什么从安卓2.0之后官方规定只能在主线程中更新界面了。子线程执行结果后通知主线程更新界面的桥梁便需要handler来帮忙,下面就深入探究一下handle的工作机制。

Handler的消息机制是一个系统,分别由handler,looper,message,messageQueue四个方面组成。先理解几个概念:handler,消息的处理者,负责消息的发送和处理。looper,消息的抽取者,处理消息的前奏。message,所谓的消息,里面包含消息Id。messageQueue,消息队列,handler发送的消息会暂存在消息队列里,然后采用FIFO先进先出的原则进行执行。Activity是在ActivityThread这个类的main方法里构造的,当构造好之后回调了OnCreate方法,之后调用UI线程的Looper.loop(),让looper开始工作,这个函数内部是一个循环也即是主线程会一直执行下去。有些人可能会问这样下去会不会很耗cpu资源,其实不是这样,UI主线程其实一直处于半活动状态,当有消息来了他就会被唤醒,当没有消息的时候就会阻塞处于休眠状态。一个线程中只能有一个looper,Looper和MessageQueue一一对应,创建一个Looper的同时,会创建一个MessageQueue。


关系图:



消息生成:

方法1:

 Message msg = handler.obtainMessage();
 msg.arg1 = i;
 msg.sendToTarget();
方法2:
Message msg=new Message();
msg.arg1=i;
handler.sendMessage(msg);
第一种写法是message 从handler 类获取,从而可以直接向该handler 对象发送消息,减少了内存空间的开辟,节省资源。

第二种写法是直接调用 handler 的发送消息方法发送消息。


发送消息:

public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
        MessageQueue queue = mQueue;
        if (queue == null) {
            RuntimeException e = new RuntimeException(
                    this + " sendMessageAtTime() called with no mQueue");
            Log.w("Looper", e.getMessage(), e);
            return false;
        }
        return enqueueMessage(queue, msg, uptimeMillis);
    }
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        msg.target = this;
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);
    }

在第一个代码片段中我们发现,handler在发送message的时候首先要找到所引用的消息队列。在第二个代码块中我们看到,Message的target设定成自己,目的是为了在处理消息环节中,Message能找到正确的Handler,最后将这个Message纳入到消息队列中。


抽取消息:

 mLooper = Looper.myLooper();
 if (mLooper == null) {
     throw new RuntimeException(
         "Can't create handler inside thread that has not called Looper.prepare()");
 }
 mQueue = mLooper.mQueue;
 mCallback = callback;
 mAsynchronous = async;

这里的looper处于一个死循环,时刻检索消息队列中的消息。


消息的分发:

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

到这一步也算是最后一步消息即将传递到位,只等回调出来了。


附加说明:

在主线程(UI线程)里,如果创建Handler时不传入Looper对象,那么将直接使用主线程(UI线程)的Looper对象,系统已经帮我们创建了;

在其它线程里,如果创建Handler时不传入Looper对象,那么,这个Handler将不能接收处理消息。所以我们要自行在handler线程中创建一个looper,让他自行的跑起来,这样才能顺利接收和分发我们的消息了。

class LooperThread extends Thread {
            public Handler mHandler;
            public void run() {
                Looper.prepare();
                mHandler = new Handler() {
                    public void handleMessage(Message msg) {
                        // process incoming messages here
                    }
                };
                Looper.loop();
            }
        }
至此今天我们针对handler,looper,messageQueue有一个中层次的探究,当然还有深一层的探究,等到后续我慢慢的再补充吧。











评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值