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了
- Looper Handler Message 总结
- Handler,Looper,Message总结
- Handler,Looper,MessageQueue,Message总结
- Looper、Message、MessageQueue、Handler归纳总结
- Looper,Handler,Message,MessageQueue
- Message,MessageQueue,Looper,Handler
- Looper Handler Message
- handler,message,Looper
- Looper,Handler,Message
- Handler Message Looper陈述
- Handler,Looper,Message
- Message Handler Looper
- Looper Handler Message
- Message,Handler,Looper,MessageQueue
- Looper,Handler,Message
- Looper,Handler,Message
- Android Handler,Looper,Message
- Looper,Message,Handler概述
- 利用DIID_DWebBrowserEvents2接口接收WebBrowser事件 .
- cocos2d-x:导演,场景,层,以及精灵的介绍
- Android中集成第三方软件包(.jar, .so)
- MVC上传图片
- 分享一篇关于iOS7力学的文章
- Looper Handler Message 总结
- 《文字与段落——使用HTML标记完成页面排版》
- linux crontab简介
- Xpath的语法
- solr4.5 mmseg4j 分词器配置
- 一步一步做ListView滚动固定头部并且头部会变化哦
- C++必知必会之(12)赋值和初始化并不相同
- 28个 HTML5新特性
- ContentPlaceHolder