Android消息机制之Handler

在Android的异步消息处理机制中,Handler发挥着重要的作用,本文从Handler源码的角度,对Handler的使用进行分析。首先来看看Handler的创建方式:

1. 在主线程可以直接通过new创建

2. 在子线程中需要先调用Looper.prepare(),再执行new操作,否则会崩溃提示:

Can't create handler inside thread that has not called Looper.prepare()

那么问题来了,为什么在子线程中不调用Looper.prepare()就会崩溃?为什么在主线程中可以直接new创建?我们先看看Handler的构造方法:

 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,其Looper对象存放在sThreadLocal对象中,我们可以猜测是Looper.prepare()调用时创建和存放,接着看Looper.prepare():

/** Initialize the current thread as a looper.
      * This gives you a chance to create handlers that then reference
      * this looper, before actually starting the loop. Be sure to call
      * {@link #loop()} after calling this method, and end it by calling
      * {@link #quit()}.
      */
    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()时创建Looper对象,然后存放到sThreadLocal中,并且一个线程只能有一个Looper对象。

至此第一个问题得解,我们来看第二个问题:为什么在主线程中直接new就不会崩溃?通过函数的引用关系,可以看到调用private static void prepare(boolean quitAllowed)的除了public static void prepare(),还有public static void prepareMainLooper(),其具体实现如下:

/**
     * Initialize the current thread as a looper, marking it as an
     * application's main looper. The main looper for your application
     * is created by the Android environment, so you should never need
     * to call this function yourself.  See also: {@link #prepare()}
     */
    public static void prepareMainLooper() {
        prepare(false);
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            sMainLooper = myLooper();
        }
    }


可见,在prepareMainLooper()中调用了prepare()。我们接着看prepareMainLooper()的引用关系,可以找到在ActivityThread的main()方法中调用了,如下:

public static void main(String[] args) {
        ......

        Looper.prepareMainLooper();

        ActivityThread thread = new ActivityThread();
        thread.attach(false);

        if (sMainThreadHandler == null) {
            sMainThreadHandler = thread.getHandler();
        }

        if (false) {
            Looper.myLooper().setMessageLogging(new
                    LogPrinter(Log.DEBUG, "ActivityThread"));
        }

        // End of event ActivityThreadMain.
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
        Looper.loop();

        throw new RuntimeException("Main thread loop unexpectedly exited");
    }

 

ActivityThread作为App的入口,在App启动时其main()方法会调用,当然就会执行prepareMainLooper(),

由此可知系统已经已经为主线程创建了Looper对象,所以我们可以直接通过new操作创建对象。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值