android Handler机制的学习

我们经常这样创建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();

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android handler机制是一种在Android中用于处理异步消息和线程通信的重要机制。其主要作用是将消息和任务抛到主线程的消息队列中,以便主线程按照一定的规则按照队列中的顺序处理这些消息和任务。 1. Handler的实例化:在Android中,创建一个Handler的实例可以通过以下两种方式实现: 直接实例化: 创建一个Hanlder对象,代码示例: Handler handler = new Handler(); 绑定Looper:在子线程中创建Handler的话,需要先通过以下代码获取Looper对象,然后再将其传入Handler的构造函数中: Looper looper = Looper.myLooper(); Handler handler = new Handler(looper); 2. Handler的使用:当一个线程需要将一个耗时的任务交给主线程去执行的时候,它可以使用Handler来完成。以下是Handler的常见用法示例: 使用Handler处理消息: Handler myHandler = new Handler() { public void handleMessage(Message msg) { //在这里处理消息 } }; Message msg = myHandler.obtainMessage(); Bundle bundle = new Bundle(); bundle.putString("my_key", "my_string"); msg.setData(bundle); myHandler.sendMessage(msg); 使用Handler更新UI: Handler myHandler = new Handler() { public void handleMessage(Message msg) { //更新UI } }; myHandler.sendEmptyMessage(0); 3. Handler的原理:在Android系统中,所有的UI操作都必须在主线程上完成。这时,Handler就扮演了一个传递任务的中介角色。它把来自子线程的消息和任务封装成Message对象,最后以一定的顺序扔到主线程的消息队列中等待执行。主线程通过Looper不断地循环读取消息队列中的消息和任务,然后依次执行。这就是Handler机制的基本原理。 4. Handler配合其他机制使用:为了更好地发挥Handler的作用,还可与一些其他机制有效配合使用,例如:AsyncTask、MessageQueue等等。通过多种机制的相互配合,可以实现复杂的异步消息处理和并发控制,提升了Android应用程序的性能和稳定性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值