android Handler机制的学习

本文深入探讨了Android中Handler和Looper的工作原理,解释了如何在主线程和子线程中正确地创建Handler对象,以及Looper.prepare()和Looper.loop()的作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

我们经常这样创建handler,和使用Handler,

Handler handler = new Handler(){
    @Override
    public void handleMessage(Message msg) {
        super.handleMessage(msg);
    }
};
handler.sendEmptyMessage(0);

但是有的时候这样创建会报错:

class LooperThread extends Thread {
    public Handler mHandler;
  
    public void run() {
        mHandler = new Handler() {
            public void handleMessage(Message msg) {
                // process incoming messages here
           }
        };
    }
}
会报错:Can't create handler inside thread that has not called Looper.prepare()

这个时候我们可能会在Handler 前后加上Looper.prepare();和 Looper.loop();

到现在,我们还没有切入正题,为什么??我们首先来看一下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());
            }
        }

        <span style="color:#ff0000;">mLooper = Looper.myLooper();</span>
        <span style="color:#ff0000;">if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread that has not called Looper.prepare()");
        }</span>
        mQueue = mLooper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }
在这里我们看到一段使用Looper代码的地方,那么Looper 又做了什么呢?我们继续往下看:

    /**
     * Return the Looper object associated with the current thread.  Returns
     * null if the calling thread is not associated with a Looper.
     */
    public static Looper myLooper() {
        return sThreadLocal.get();
    }
Looper 想要获取于当前线程绑定的 Looper 对象。可是我们自己并没有创建,那是谁给我们创建了,发现在ActivityThread中 已经帮我们初始化:


在Looper中 prepareMainLooper 的方法如下:

    public static void prepareMainLooper() {
        prepare(false);
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            sMainLooper = myLooper();
        }
    }
    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,但是在主线程中,ActivityThread 初始化的时候已经为我们创建了主线程的 Looper 对象,所以我们在主线程不需要在创建Looper对象了,只需要绑定Handler 对象就可以,所以主线程中可以创建多个Handler对象,同样在子线程中,如果我们需要创建Handler 对象就必须先调用 Looer.prepare()方法创建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;

        // 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();

        <span style="color:#cc0000;">for (;;) </span>{
            <span style="color:#cc0000;">Message msg = queue.next(); // might block</span>
            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);
            }

            <span style="color:#cc0000;">msg.target.dispatchMessage(msg);</span>

            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.recycle();
        }
    }
我们可以看到loop 方法起始就是一个循环调用队列,获取队列消息,并交给对应的 Handler 去处理消息。它可以保证当前线程不被销毁回收。所以在退出activity时确保消息队列里面没有消息等待处理,可以手动调用Handler.removeMessages();
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值