Looper Handler Message 总结


先来看一下我自己写的一个有关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:1
Thread-0:2
Thread-0:3
Thread-0:4
Thread-0:5
Thread-1:1
Thread-1:2
Thread-1:3
Thread-1:4
Thread-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.start
Looper  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了







 










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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值