美文网首页
HandlerThread和Handler,Message,Lo

HandlerThread和Handler,Message,Lo

作者: Qi0907 | 来源:发表于2017-04-26 17:28 被阅读0次

    1、HandlerThread
    Thread线程是一次性消费品,当Thread线程执行完一个任务之后,线程就会被自动销毁了。如果此时又有一个任务需要执行,就得重新创建一个线程这样多次创建和销毁线程是很耗系统资源的,因此会有性能问题。为了解这个问题,可以构建一个循环线程Looper Thread,当有任务放到该循环线程中时,线程执行任务,执行完之后循环线程处于等待状态,直到下一个新的任务被放进来。这样就避免了多次创建Thread。这个问题可以使用HandlerThread,他的父类是Thread,因此HandlerThread其实是一个线程,只不过内部实现了一个Looper的循环,他依次从Handler的队列中获取信息,逐个进行处理,保证安全,不会出现混乱引发的异常。

    public class HandlerThread extends Thread {
    
        @Override
        public void run() {
            mTid = Process.myTid();
            Looper.prepare();//创建与线程关联的Looper对象
            //进入同步块,当前线程已经创建myLooper对象成功
            //调用notifyAll通知其他阻塞在当前对象上的线程,主要是通知getLooper中的wait
            synchronized (this) {
                mLooper = Looper.myLooper();
                notifyAll();
            }
            Process.setThreadPriority(mPriority);
            onLooperPrepared();
            Looper.loop();//启动loop
            mTid = -1;
        }
    
        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 {// 直到mLooper创建成功,才退出while,run方法里的notifyAll就是用来唤醒这里的
                        wait();
                    } catch (InterruptedException e) {
                    }
                }
            }
            return mLooper;
        }
    

    2、Handler,message,looper
    它们之间的关系如下:
    (1)Looper:相当于消息的载体
    • 它的内部有一个消息队列,也就是MessageQueue,Handler发送的所有消息都会走向这个消息队里。
    • 它的Looper.loop方法是一个死循环,不断的从消息队列MessageQueue中取出消息。如果有消息存在就处理该消息,否则就阻塞。
    (2)MessageQue:是一个消息队列,可以向其中添加消息并处理消息。
    (3)Handler:是发送消息处理消息的封装。它与Looper相关联,也就是说在Handler的内部可以找到Looper,找到了Looper就找到了相应的消息队列。因此Handler发送的消息都会走向MessageQueue。
    也就是说Handler负责发送消息和接收Looper传过来的消息,并根据消息处理相应逻辑,Looper负责接收Handler发送过来的消息,并将该消息回传给Handler。而MessageQueue只是相当于一个消息容器


    Paste_Image.png

    (1)Looper
    Looper主要有prepare()和loop()两个方法
    A、先看prepare()方法:

    private static void prepare(boolean quitAllowed) {
            //判断了sThreadLocal是否为null,
            //说明了Looper.prepare()方法不能被调用两次,也保证了一个线程中只有一个Looper实例
            if (sThreadLocal.get() != null) {
                throw new RuntimeException("Only one Looper may be created per thread");
            }
            sThreadLocal.set(new Looper(quitAllowed));//将一个Looper的实例放入了ThreadLocal
        }
    

    sThreadLocal是一个ThreadLocal对象,可以在一个线程中存储变量。
    (当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本,在ThreadLocal类中有一个Map,用于存储每一个线程的变量副本,Map中元素的键为线程对象,而值对应线程的变量副本,对于多线程资源共享的问题,同步机制采用了“以时间换空间”的方式,而ThreadLocal采用了“以空间换时间”的方式。前者仅提供一份变量,让不同的线程排队访问,而后者为每一个线程都提供了一份变量,因此可以同时访问而互不影响)

    static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
    

    B、new Looper(quitAllowed):

    private Looper(boolean quitAllowed) {
            mQueue = new MessageQueue(quitAllowed);//创建了一个MessageQueue(消息队列)
            mThread = Thread.currentThread();
        }
    

    C、再看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;//拿到该looper实例中的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.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.recycleUnchecked();//释放消息占据的资源
            }
        }
    

    第二行,关于myLooper:

        public static Looper myLooper() {
            //返回了sThreadLocal存储的Looper实例,如果为null则抛出异常
            //也就是说looper方法必须在prepare方法之后运行
            return sThreadLocal.get();
        }
    

    可以看到Looper主要作用:
    1、 与当前线程绑定,保证一个线程只会有一个Looper实例,同时一个Looper实例也只有一个MessageQueue。
    2、 loop()方法,不断从MessageQueue中去取消息,交给消息的target属性的dispatchMessage去处理。

    (2)Handler:
    A、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();//获取了当前线程保存的Looper实例
            if (mLooper == null) {
                throw new RuntimeException(
                    "Can't create handler inside thread that has not called Looper.prepare()");
            }
            //获取了这个Looper实例中保存的MessageQueue(消息队列)
            //这样handler的实例与我们Looper实例中MessageQueue关联上了
            mQueue = mLooper.mQueue;
            mCallback = callback;
            mAsynchronous = async;
        }
    

    B、发送消息sendMessage

    public final boolean sendMessage(Message msg)
        {
            return sendMessageDelayed(msg, 0);
        }
    
    public final boolean sendMessageDelayed(Message msg, long delayMillis)
        {
            if (delayMillis < 0) {
                delayMillis = 0;
            }
            return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
        }
    
    public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
            MessageQueue queue = mQueue;
            if (queue == null) {
                RuntimeException e = new RuntimeException(
                        this + " sendMessageAtTime() called with no mQueue");
                Log.w("Looper", e.getMessage(), e);
                return false;
            }
            return enqueueMessage(queue, msg, uptimeMillis);
        }
    
    private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
            //Looper的loop方法会取出每个msg然后交给msg.target.dispatchMessage(msg)去处理消息
            //也就是把当前的handler作为msg的target属性
            msg.target = this;
            if (mAsynchronous) {
                msg.setAsynchronous(true);
            }
            return queue.enqueueMessage(msg, uptimeMillis);//保存到消息队列中
        }
    

    C、消息分发:

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

    为什么是一个空方法呢?因为消息的最终回调是由我们控制的,我们在创建handler的时候都是复写handleMessage方法,然后根据msg.what进行消息处理
    例如:

    private Handler mHandler = new Handler()  
        {  
            public void handleMessage(android.os.Message msg)  
            {  
                switch (msg.what)  
                {  
                case value:  
                      
                    break;  
      
                default:  
                    break;  
                }  
            };  
        };
    

    总结:
    1、首先Looper.prepare()在本线程中保存一个Looper实例,然后该实例中保存一个MessageQueue对象;因为Looper.prepare()在一个线程中只能调用一次,所以MessageQueue在一个线程中只会存在一个。
    2、Looper.loop()会让当前线程进入一个无限循环,不端从MessageQueue的实例中读取消息,然后回调msg.target.dispatchMessage(msg)方法。
    3、Handler的构造方法,会首先得到当前线程中保存的Looper实例,进而与Looper实例中的MessageQueue想关联。
    4、Handler的sendMessage方法,会给msg的target赋值为handler自身,然后加入MessageQueue中。
    5、在构造Handler实例时,我们会重写handleMessage方法,也就是msg.target.dispatchMessage(msg)最终调用的方法

    相关文章

      网友评论

          本文标题:HandlerThread和Handler,Message,Lo

          本文链接:https://www.haomeiwen.com/subject/lempzttx.html