Android HandlerThread Handler Looper 三类之间的联系--学习

最近在学习Android的多线程编写技术,对这段时间的学习小小的总结下,纯属新手,勿喷。

下面来简单的说下三个类的作用,Android的应用程序都是靠消息队列来工作的,消息队列和消息处理的回调函数。说说3个类在这个机制里面分别担任了什么角色?

Handler类,我把它比作为消息的消息的快递人员吧,形象比较相近。它主要对消息队列添加消息,分发消息,把消息从队列里移除,获取消息队列,延时插入消息,等等作用,我们每个Handler对象都需要绑定一个Looper对象,为什么?因为之后介绍Looper的时候再说。

Looper类,它是Android线程消息处理的最基本子对象。每个线程基本都包含这个类的对象。我们从它的构造函数看看:

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

我们可以看到它会创建一个消息队列,还有它所处的线程ID。它的作用是什么?就是消息的载体,消息在哪里跑?就在Looper里面。所以每个线程都有一个消息队列。里面还有一个很重要的的函数:

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

这个是获取当前线程的Looper对象,它的作用什么?上面说了,Handler对象在创建时,都会绑定一个looper对象,这个时候就需要用这个函数。通过对Looper的描述,大家有没有想明白为什么Handler一定要绑定一个Looper对象?

HandlerThread类,它的出现,是为了防止我们在使用Looper和Handler时候,出现的一些问题,简化我们的操作。下面来举个例子:

假如我们在进行多线程处理,如下代码,

//代码2
class TestThread extends Thread{
      public Looper myLooper = null;

public void run(){
                Looper.prepare();//创建Looper对象
           myLooper = Looper.myLooper();//初始化线程的Looper子对象。
          Looper.loop();
                 
}
}
//代码1
{
TestThread ydThread = new LooperThread;
      ydThread.start();//创建线程2
     Looper looper = ydThread.myLooper;//这里是有问题的,具体为什么,待会再说。
 //这里创建线程2的处理Handler
Handler threadHandler = new Handler(looper);
// sendMessage 发送的消息给线程2处理
threadHandler.sendMessaage(...);
}

先来说说上面代码的目的,首先在线程1中创建一个线程2,想通过线程2来处理一些即时消息,根据线程2的Looper对象,创建消息处理对象Handler。注意,Handler对象在线程1创建的,也就是说,Handler的绑定对象Looper是从线程2里面获取出来的,两个线程在跑的过程中,不一定谁跑的快,所以,在线程1获取的线程2Looper对象有可能是空的,如果获取的Looper对象为空,那么Handler将不会有对消息的处理能力。就没达到线程2处理消息的目的。这时候怎么来解决?Android原生用HandlerThread来避免这个情况。

   public Looper getLooper() {
        if (!isAlive()) {
            return null;
        }
        
        // If the thread has been started, wait until the looper has been created.
        synchronized (this) {
            while (isAlive() && mLooper == null) {
                try {
                    wait();
                } catch (InterruptedException e) {
                }
            }
        }
        return mLooper;
    }

我们在初始化Handler时候,使用这个接口,我们可以看到里面加了同步处理wait();在线程的运行run中:

    public void run() {
        mTid = Process.myTid();
        Looper.prepare();
        synchronized (this) {
            mLooper = Looper.myLooper();
            notifyAll();
        }
        Process.setThreadPriority(mPriority);
        onLooperPrepared();
        Looper.loop();
        mTid = -1;
    }


首先prepare中创建Looper对象,然后赋值,通知Looper已经创建好了,可以使用了。就能避免上述的错误情况出现。

所以上述的代码我们可以改成这样:

//代码1
{
HandlerThread ydThread = new HandlerThread ;
      ydThread.start();//创建线程2
     Looper looper = ydThread.getLooper();//这里是有问题的,具体为什么,待会再说。
 //这里创建线程2的处理Handler
Handler threadHandler = new Handler(looper);
// sendMessage 发送的消息给线程2处理
threadHandler.sendMessaage(...);
}

这样,就不会有问题了。
现在来说说Handler对消息的处理,当Handler将消息send到Looper的消息队列中,系统会去从队列的头开始取消息,然后在Looper中进行如下处理:

    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.recycle();
        }
    }

交给msg.target.dispatchMessage分发下去。最后会发给Handler的dispatchMessage:

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

从上面的代码可以看出首先看消息时候是否有回调函数,再看Handler的mCallback对象是否为空,这个在创建的时候都默认null,最后使用派生的handleMessage函数。

下面举个使用第一种方法的例子:

        HandlerThread thr = new HandlerThread("SystemUI StorageNotification");
        thr.start();
        mAsyncEventHandler = new Handler(thr.getLooper());
    @Override
    public void onUsbMassStorageConnectionChanged(final boolean connected) {
        mAsyncEventHandler.post(new Runnable() {
            @Override
            public void run() {
                onUsbMassStorageConnectionChangedAsync(connected);
            }
        });
    }


首先创建HandlerThread线程2,再创建一个Handler mAsyncEventHandler。使用handler的post方法,初始化消息的Callback。看post方法:

    public final boolean post(Runnable r)
    {
       return  sendMessageDelayed(getPostMessage(r), 0);
    }
    private static Message getPostMessage(Runnable r) {
        Message m = Message.obtain();
        m.callback = r;
        return m;
    }

首先用onUsbMassStorageConnectionChangedAsync(connected);初始化Message的callback,最后在线程1得到的消息,都onUsbMassStorageConnectionChangedAsync函数中处理。至此,3者的关系处理结束!

纯属个人意见,有问题,请指点,谢谢!


     







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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值