Android中Handler机制解析

Handler机制在Android系统中非常重要。由于Android系统不能在非主线程更新UI,只能在主线程中更新UI,那么当需要在非主线程更新UI时,就需要Handler机制的帮助,进行线程的切换。这也是Handler机制最平常的用法。当然利用Handler机制也可以制作一个简易的网络请求框架。
那么就从AS中一窥Handler的源码。
图如下:
这里写图片描述
从AS中看Handler的源码
首先:
Looper: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()方法,可以看到从ThreadLocal中去拿Looper,如果拿不到,就将新new一个Looper,存放在ThreadLocal中,如果拿的到就抛出一个异常——一个线程中只能有一个Looper,也就要是说如果线程中已经有Looper了,就不能在调用Looper的prepare()方法了。即Looper的prepare()方法只能调用一次。同时注意ThreadLocal:线程本地变量,属于线程的私有空间,将Looper保存在ThreadLocal中,保证了Looper不会被其他线程干扰,是线程安全的,一种空间换时间的同步方式。
总结:通过prepare()方法,Looper与所在的线程绑定(放在了ThreadLocal中),保证了一个线程只能有一个Looper。
再看Looper的构造方法

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

可以看到Looper的构造方法是私有的,不能实例化,同时可以看到mQueue = new MessageQueue(quitAllowed);实例化了消息队列,也就是说Looper在prepare()后,组合了MessageQueue,一个Looper就对应一个MessageQueue,同时对应了所在线程。MessageQueue不深究,就是一队列,缓存Message的。
在看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;

        // Make sure the identity of this thread is that of the local process,
        // and keep track of what that identity token actually is.
        Binder.clearCallingIdentity();
        final long ident = Binder.clearCallingIdentity();

        for (;;) {
            Message msg = queue.next(); // might block
            if (msg == null) {
                // No message indicates that the message queue is quitting.
                return;
            }

            // This must be in a local variable, in case a UI event sets the logger
            Printer logging = me.mLogging;
            if (logging != null) {
                logging.println(">>>>> Dispatching to " + msg.target + " " +
                        msg.callback + ": " + msg.what);
            }

            msg.target.dispatchMessage(msg);

            if (logging != null) {
                logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
            }

            // Make sure that during the course of dispatching the
            // identity of the thread wasn't corrupted.
            final long newIdent = Binder.clearCallingIdentity();
            if (ident != newIdent) {
                Log.wtf(TAG, "Thread identity changed from 0x"
                        + Long.toHexString(ident) + " to 0x"
                        + Long.toHexString(newIdent) + " while dispatching to "
                        + msg.target.getClass().getName() + " "
                        + msg.callback + " what=" + msg.what);
            }

            msg.recycleUnchecked();
        }
    }

首先获得所在线程中的Looper

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

然后for (;;) 死循环,去拿MessageQueue中的Message,然后调用*msg.target.dispatchMessage(msg)*;
注意这句话,然后将message回收。loop方法完了,疑问:msg的target是谁,dispatchMessage(msg)方法做了什么?
带着疑问来看Handler:
首先构造方法:

public Handler() {
        this(null, false);
    }

public Handler(Callback callback, boolean async) {
        if (FIND_POTENTIAL_LEAKS) {
            final Class<? extends Handler> klass = getClass();
            if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
                    (klass.getModifiers() & Modifier.STATIC) == 0) {
                Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
                    klass.getCanonicalName());
            }
        }

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

在Handler实例化后,得到了所在线程的Looper(mLooper = Looper.myLooper();),如果Looper为null抛出异常,即没有调用Looper.prepare(),Handler不能实例化,也就是说,想要使用Handler必须在Looper的prepare()调用之后。然后得到了Looper中的MessageQueue(mQueue = mLooper.mQueue;),ok,组合关系很清楚了,继续:
使用Handler最常用的方法就是sendMessage,字面来看,推一个消息,推到哪呢?
sendMessage(Message msg),sendEmptyMessage(int what),sendMessageDelayed(msg, 0),sendMessageAtTime,post(Runnable r),postAtTime(Runnable r, long uptimeMillis),postDelayed(Runnable r, long delayMillis),都调用了

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

都是将Message推入Handler对应的Looper的MessageQueue中,注意msg.target = this这句话,之前分析Looper时,其loop()方法调用了msg.target.dispatchMessage()方法,这里就可以看到msg.target就是推送Message的Handler,在loop中调用了handler的dispatchMessage(Message msg)方法

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

我们看到如果Message的callback不为null,就执行handleCallback(msg),那么什么时候Message的callback不为null呢,看源码可知post系列方法中Message的callback不为null,send系方法中Message的callback为null,在msg.callback != null时,就执行Runnable中的run()方法。那么在msg.callback == null时,调用了handleMessage(msg),好熟悉的函数,在实例化Handler时,都会实现该方法来处理Message,看下该方法做了什么?

public void handleMessage(Message msg) {
    }

一个空的方法,在实例化Handler是我们复写了handleMessage方法,具体对Message怎么处理,我们自己决定。由此一些都清楚了。
总结如下:
在使用Handler的时候,必须进行执行Looper的prepare()方法,即准备好资源,Looper与当前线程的绑定,MessageQueue的实例化,否则会抛出异常,随后Handler实例化,即取出当前线程中的Looper,拿到Looper的MessageQueue,在我们调用sendxxx或者postxxx方法时,将Message推送到Looper对应的MessageQueue中,同时将Message的target设置为本身(Handler),这是Looper调用了loop()方法,不断从MessageQueue中取出Message,调用msg.target.dispatchMessage,即Handler的dispatchMessage方法,在该方法中全都是我们自己的逻辑了,我们复写handleMessage处理传过来的Message,或者按照自己的意愿执行Runnable的run方法。至此Message就可以在不同线程间到处游蹿,最终回到Handler所在的线程,实现线程间信息的传递和交互。
从上面的总结可以看到使用Handler正确的顺序是:
Looper.prepare()–>new Handler()—>Looper.loop()
最后说明,在Activity中使用Handler时,为什么没有见到Looper.prepare()和Looper.loop(),因为在主线程中,已经默认开启了,系统已经为我们做过了这些工作。
至此Handler的分析完成。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值