Android Handler中的handleMessage方法和post方法之源码剖析

本文深入剖析Android Handler的handleMessage和post方法。通过源码分析,解释了Handler创建、消息发送、MessageQueue的工作原理,以及如何通过这两种方法在主线程中更新UI。同时,建议使用obtainMessage()而非new Message()以节省内存。post方法的本质是通过Runnable的run方法在主线程中执行,与handleMessage方法效果相同。
摘要由CSDN通过智能技术生成

我们都知道,在子线程中进行UI操作(更新UI控件)包括以下四种方法:

1.Handler的handlerMessage()方法。

2.Handler的post()方法。

3.View的post()方法。

4.Activity的runOnUiThread()方法。

本文重点分析前两种方法,后面两种稍微说一下。在说第一个方法之前,让我们先来看张图片(图片来源于http://my.oschina.net/keeponmoving/blog/61129)



这个图片在很好的说明了Handler中的handleMessage方法的工作原理(至少说明了怎么回事)。但是这个图有个问题,作者把handleMessage画到了主线程的外面,其实应该是要在主线程里面,这样才能通过handleMessage来操作主线程的ui,接下来详细说明原因:

先看看如何创建handler吧,其构造函数如下:

public Handler() {
    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 followingHandler class should be static or leaks might occur: " +
                klass.getCanonicalName());
        }
    }
    mLooper = Looper.myLooper();
    if (mLooper == null) {
        throw new RuntimeException(
            "Can't create handler insidethread that has not called Looper.prepare()");
    }
    mQueue = mLooper.mQueue;
    mCallback = null;
}

可以看到,mLooper = Looper.myLooper();创建了一个新的Looper对象,mLooper不能为空,如果为空则会抛出异常,我们来看下Looper.myLooper()这个方法:

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

这个方法功能很简单,就是从sThreadLocal线程中取出Looper对象。如果sThreadLocal线程有Looper对象则返回,如果没有则返回空。那什么时候给sThreadLocal线程设定的Looper对象呢?来看看Looper.prepare()方法吧:

public static finalvoid prepare() {
    if (sThreadLocal.get() != null) {
        throw new RuntimeException("Onlyone Looper may be created per thread");
    }
    sThreadLocal.set(new Looper());
}

其实,我们在使用Handler之前需要调用Looper.prepare()方法,那为什么我们一般在主线程中根本没有调用这个方法啊,其实系统已经帮我们调用了的。ActivityThread中的main()方法源码:

public static void main(String[] args) {
    SamplingProfilerIntegration.start();
    CloseGuard.setEnabled(false);
    Environment.initForCurrentUser();
    EventLogger.setReporter(newEventLoggingReporter());
    Process.setArgV0("<pre-initialized>");
    Looper.prepareMainLooper();
    ActivityThread thread = new ActivityThread();
    thread.attach(false);
    if (sMainThreadHandler == null) {
        sMainThreadHandler =thread.getHandler();
    }
    AsyncTask.init();
    if (false) {
        Looper.myLooper().setMessageLogging(newLogPrinter(Log.DEBUG, "ActivityThread"));
    }
    Looper.loop();
    throw new RuntimeException("Mainthread loop unexpectedly exited");
}

上面代码的第7行就已经调用了Looper.prepare方法(读者可以继续查看Looper.prepareMainLooper()源代码)。
创建好了handler之后,我们再使用的时候需要调用sendMessage()方法,看代码sendMessage():

Message message = newMessage(); 
mHandler.sendMessage(message);

从上面的代码可以看出,每次sendMessage的时候都需要先new一个

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值