Looper Handler Message 总结

来源:互联网 发布:网络哲学百科 编辑:程序博客网 时间:2024/05/13 22:30


先来看一下我自己写的一个有关ThreadLocal的例子,让我们来熟悉下ThreadLocal的用法

public class TestThreadLocal {private static ThreadLocal<Integer> a = new ThreadLocal<Integer>() {public Integer initialValue() { return 0;}};public static void main(String args[]) {MyThread my = new MyThread();my.start();MyThread myThread2 = new MyThread();myThread2.start();}public static class MyThread extends Thread {public void run() {for (int i = 0; i < 5; i++) {a.set(a.get() + 1);System.out.println(Thread.currentThread().getName() + ":"+ a.get());}}}}

输出:

Thread-0:1Thread-0:2Thread-0:3Thread-0:4Thread-0:5Thread-1:1Thread-1:2Thread-1:3Thread-1:4Thread-1:5

从输出很容易看出ThreadLocal<Integer> a是每个线程都有一份变量,而且ThreadLocal的set/get只和当前线程有关,请记住这个java的基本知识


接着看Looper类的定义

/**  * Class used to run a message loop for a thread.  Threads by default do  * not have a message loop associated with them; to create one, call  * {@link #prepare} in the thread that is to run the loop, and then  * {@link #loop} to have it process messages until the loop is stopped.  *   * <p>Most interaction with a message loop is through the  * {@link Handler} class.  *   * <p>This is a typical example of the implementation of a Looper thread,  * using the separation of {@link #prepare} and {@link #loop} to create an  * initial Handler to communicate with the Looper.  *  * <pre>  *  class LooperThread extends Thread {  *      public Handler mHandler;  *  *      public void run() {  *          Looper.prepare();  *  *          mHandler = new Handler() {  *              public void handleMessage(Message msg) {  *                  // process incoming messages here  *              }  *          };  *  *          Looper.loop();  *      }  *  }</pre>  */public class Looper {

从Looper的定义来看,是说明的很清楚了,我们就按官方的这个例子来说明一个个例子中的方法分析,假设调用了LooperThread().start();执行

一、Looper.prepare();

二、 Looper.loop();


先看Looper.prepare();

    static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();    public static void prepare() {        if (sThreadLocal.get() != null) {            throw new RuntimeException("Only one Looper may be created per thread");        }        sThreadLocal.set(new Looper());    }
上面构造了一个Looper对象,并且放入调用线程的局部变量中,即线程的局部变量sThreadLocal存储的是Looper对象,这个Looer对象只针对当前的线程操作


看下new Looper()构造方法做了什么

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

上面代码主要做了两件事

1、mQueue = new MessageQueue();构造了MessageQueue

2、mThread = Thread.currentThread();得到当前线程对象


接着看Looper.loop();

    public static void loop() {        Looper me = myLooper();             MessageQueue queue = me.mQueue;           while (true) {            Message msg = queue.next(); // might block            if (msg != null) {                if (msg.target == null) {                                     return;                }                         msg.target.dispatchMessage(msg);                      msg.recycle();            }        }    }

上面的Looper me = myLooper();去除消息队列中的消息然后while循环一直检查是否有消息,如果有消息则执行下面这一句

 msg.target.dispatchMessage(msg);

我们需要注意上面的msg.target的类型是          

Handler target;    

 这里特别要注意  就是说最后还是交给了 Message 的 target ( Handler 类型)dispatchMessage(msg) 处理

我们后续需要注意下message封装消息的时候是否把Hanlder赋值给Message的target


我们接着看上面的Looper me = myLooper();

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

就是返回当前线程的ThreadLocal 对象sThreadLocal存储的Looper,而Looper的构造方法里面有其消息队列,所以会有loop方法中的

 MessageQueue queue = me.mQueue;
从上面我们可以总结

1、Looper的prepare函数把Looper和prepare的线程(处理线程)绑定在一起

2、Looper构造函数封装了一个消息队列

3、处理线程调用loop函数,while一直在处理消息队列里面的消息


那么我们的消息是怎么放入消息队列的呢?我们接着看Hanlder类,先看Handler类的成员属性

    final MessageQueue mQueue;    final Looper mLooper;    final Callback mCallback;

从上面来看Handler也有一个MessageQueue和一个Looper还有一个回调

我们接这看它的构造函数

    public Handler() {        mLooper = Looper.myLooper();        if (mLooper == null) {            throw new RuntimeException(                "Can't create handler inside thread that has not called Looper.prepare()");        }        mQueue = mLooper.mQueue;        mCallback = null;    }

  public Handler(Callback callback) {          mLooper = Looper.myLooper();        if (mLooper == null) {            throw new RuntimeException(                "Can't create handler inside thread that has not called Looper.prepare()");        }        mQueue = mLooper.mQueue;        mCallback = callback;    }

    public Handler(Looper looper) {        mLooper = looper;        mQueue = looper.mQueue;        mCallback = null;    }

    public Handler(Looper looper, Callback callback) {        mLooper = looper;        mQueue = looper.mQueue;        mCallback = callback;    }

从上面的重载的构造函数来看,就是Looper有可能是传入的有可能是当前线程的,还有个区别就是callback是否为空

Hanlder主要做了些什么事呢?我们来看下他的一些方法

1、obtainMessage 创建消息

2、sendMessage  加入消息队列

3、hasMessages 判断队列中是否还有消息

4、removeMessages 移除消息

我们看怎么把消息加入到消息队列的,我们接着看

    public boolean sendMessageAtTime(Message msg, long uptimeMillis)    {        boolean sent = false;        MessageQueue queue = mQueue;        if (queue != null) {            msg.target = this;            sent = queue.enqueueMessage(msg, uptimeMillis);        }        else {            RuntimeException e = new RuntimeException(                this + " sendMessageAtTime() called with no mQueue");            Log.w("Looper", e.getMessage(), e);        }        return sent;    }

上面的代码其中分析如下:

1、MessageQueue queue = mQueue 这里的mQueue是Handler的变量成员,是通过Handler构造器里面通过mLooper.mQueue而来的,而这个mLooper有可能是构造器传入的参数,也有可能是当前的执行线程的Looper

2、 msg.target = this; 解决了我之前的疑问======》我们后续需要注意下message封装消息的时候是否把Hanlder赋值给Message的target

3、queue.enqueueMessage(msg, uptimeMillis);把封装的消息放入消息队列,有关enqueueMessage这个方法这里就不展开了:通过这个方法的注释已经说明的很清楚:Enqueue a message into the message queue after all pending messages


上面都是消息封装,我们来看下其消息是怎么处理的

    /**     * Handle system messages here.     */    public void dispatchMessage(Message msg) {        if (msg.callback != null) {            handleCallback(msg);        } else {            if (mCallback != null) {                if (mCallback.handleMessage(msg)) {                    return;                }            }            handleMessage(msg);        }    }

上面的代码的意思是如果Message的callback没有,则执行Hanlder的callback,如果Hanlder也没有callback,则执行handleMessage,有关这个callback就是一个回调,正常在封装消息或Handler的时候是一个Runnable如下面

    public final boolean postDelayed(Runnable r, long delayMillis)    {        return sendMessageDelayed(getPostMessage(r), delayMillis);    }

    private final Message getPostMessage(Runnable r) {        Message m = Message.obtain();        m.callback = r;        return m;    }

下面是展示的一个有关回调的一个例子

 private final Handler handler = new Handler() {          public void handleMessage(Message msg) {              super.handleMessage(msg);              switch (msg.what) {              case MSG_TIMER:                  mWorker = new HandlerThread("MyWorker");                  mWorker.start();                  mWorkerHandler = new Handler(mWorker.getLooper());                  mWorkerHandler.postDelayed(new MessageReceiveTask(),                          SECONDRESOLVERMESSAGE);                  break;              }          }      };          public void onCreate() {          super.onCreate();          Log.i(Constant.TAG_INFO,                  "StartService*****************************************");          Message msgget = Message.obtain();          msgget.what = MSG_TIMER;          handler.sendMessageDelayed(msgget, SECONDRESOLVERMESSAGELONG);      }            class MessageReceiveTask implements Runnable {          public void run() {              try {                  loadInitInboxData();              } catch (Exception e) {                  Log.i(Constant.TAG_EXCEPTION, "MessageReceiveTask  :  " + e);              }              mWorkerHandler.postDelayed(this, SECONDRESOLVERMESSAGE);          }      }  

我们再回到刚开始Looper例子

  class LooperThread extends Thread {        public Looper myLooper = null;        public Handler mHandler;          public void run() {            Looper.prepare();              myLooper = Looper.myLooper();              Looper.loop();        }    }
LooperThread thread1 = new LooperThread()thread1.startLooper  lp = thread1.myLooper;Hanlder hanler = new Handler(lp);hanler.sendMessage();
从上面来看,主要的处理是放在非主线程中执行的

所以

Handler handler = new Handler(looper)

不能写成

Handler handler = new Handler(Looper.myLooper())

这里的Looper.myLooper()是主线程的

那么它又是怎么解决上面的问题呢,源码中的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;    }

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

从上面来看是在非主线程中创建了looper,然后通过notifyAll来唤醒直接返回非主线程的mLooper,下面是更好的说明的之前的例子

  mWorker = new HandlerThread("MyWorker");                  mWorker.start();                  mWorkerHandler = new Handler(mWorker.getLooper());                  mWorkerHandler.postDelayed(new MessageReceiveTask(),                          SECONDRESOLVERMESSAGE);  

到此基本ok了







 










原创粉丝点击