HandlerThread和Handler,Message,Lo

2017-04-26  本文已影响0人  Qi0907

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)最终调用的方法

上一篇下一篇

猜你喜欢

热点阅读