Android开发笔记1:Handler、Looper、ThreadLocal的那些事
来源:互联网 发布:淘宝卖家运营 编辑:程序博客网 时间:2024/05/21 06:25
Handler和Looper的关系
使用过Handler的同学都应该知道,Handler最重要的两个方法就是sendMessage等发消息的方法和handleMessage处理消息的方法,下面就看看线程间是怎么通过Handler进行通信的。
1、Handler的默认构造方法
从中可以看到初始化了成员变量mLooper = Looper.myLooper(),mQueue = mLooper.mQueue
其实就是Looper mLooper 和 MessageQueue mQueue,mQueue就是存放Message的消息队列,同时消息队列是保存在Looper中的,至于为什么要把消息队列保存在Looper中,我们之后会进行说明。
public Handler() { 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(); if (mLooper == null) { throw new RuntimeException( "Can't create handler inside thread that has not called Looper.prepare()"); } mQueue = mLooper.mQueue; mCallback = null; }
2、发送消息
sendMessage等发送消息的方法最终都会执行下面的方法,我们看到其实就是把要发送的消息Message msg和对应的发送时间uptimeMillis放到消息队列mQueue中
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; }
3、处理消息
那么什么时候才会处理这些发送的消息呢?没错接下来就是Looper登场了。
1)首先代码中初始化Looper me = myLooper();
这已经是第二次调用mLooper()来初始化了,所以这里多说一句,在使用myLooper()初始化前一定要调用Looper.prepare()来把Looper添加到sThreadLocal
public static final void prepare() { if (sThreadLocal.get() != null) { throw new RuntimeException("Only one Looper may be created per thread"); } sThreadLocal.set(new Looper()); }看到没,实际就是从sThreadLocal中取出来的,所以用之前一定得set啊
public static final Looper myLooper() { return (Looper)sThreadLocal.get(); }
2)在loop方法中我们看到有一行msg.target.dispatchMessage(msg),没错就是这里执行的。
public static final void loop() { Looper me = myLooper(); MessageQueue queue = me.mQueue; while (true) { Message msg = queue.next(); // might block //if (!me.mRun) { // break; //} if (msg != null) { if (msg.target == null) { // No target is a magic identifier for the quit message. return; } if (me.mLogging!= null) me.mLogging.println( ">>>>> Dispatching to " + msg.target + " " + msg.callback + ": " + msg.what ); msg.target.dispatchMessage(msg); if (me.mLogging!= null) me.mLogging.println( "<<<<< Finished to " + msg.target + " " + msg.callback); msg.recycle(); } } }
接着往下看,下面代码就会执行handleMessage来处理消息。并且如果你调用了Handler中的post(Runnable r)等方法,那么msg.callback != null 那么就会执行handleCallback(msg)
public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } }
结论:处理消息必须要执行Looer.loop(),而执行Looper.loop()就需要先Looper.prepare(),那么为什么大多数时候我们并没有显示调用Looper.prepare() Looper.loop()呢?
主线程(ActivityThread)
1、首先看下main函数里做了什么
1)从下面的代码中可以看到,在主线程的main()方法中,调用了Looper.prepareMainLooper()和Looper.loop()
是不是很像之前讲的的Looper.prepare(),Looper.loop()?
public static final void main(String[] args) { SamplingProfilerIntegration.start(); Process.setArgV0("<pre-initialized>"); Looper.prepareMainLooper(); ActivityThread thread = new ActivityThread(); thread.attach(false); Looper.loop(); if (Process.supportsProcesses()) { throw new RuntimeException("Main thread loop unexpectedly exited"); } thread.detach(); String name = (thread.mInitialApplication != null) ? thread.mInitialApplication.getPackageName() : "<unknown>"; Slog.i(TAG, "Main thread of " + name + " is now exiting"); }
2)看看prepareMainLooper()方法不难发现,原来这个方法中就调用了Looper.prepare()方法。
public static final void prepareMainLooper() { prepare(); setMainLooper(myLooper()); if (Process.supportsProcesses()) { myLooper().mQueue.mQuitAllowed = false; } }
结论:主线程里我们并不需要显示调用,但是子线程中一定记得要显示调用Looper.prepare()和Looper.loop()
ThreadLocal
我们还记得在Looper.prepare()中调用过sThreadLocal.set(new Looper()),下面重贴下代码。
注意:每个线程只有一个Looper对象,因为每个Thread只有一个ThreadLocalMap对象并且都以key为ThreadLocal.this存储。那么在一个线程中实现多个Handler就没有意义了,因为他们都使用同一个Looper对象来保存消息。
public static final void prepare() { if (sThreadLocal.get() != null) { throw new RuntimeException("Only one Looper may be created per thread"); } sThreadLocal.set(new Looper()); }
而set方法实际上就是通过当前线程获得ThreadLocalMap,并把Looper放到当前线程的ThreadLocalMap中,并以ThreadLocal.this为key。
public void set(T value) { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value); }
ThreadLocalMap getMap(Thread t) { return t.threadLocals; }
void createMap(Thread t, T firstValue) { t.threadLocals = new ThreadLocalMap(this, firstValue); }
- Android开发笔记1:Handler、Looper、ThreadLocal的那些事
- Android笔记--ThreadLocal,Looper,Handler,Message,MessageQueue的关系
- android那些事--- Handler和Looper的纯洁关系
- Handler Looper MessageQueue HandlerThread的那些事
- Handler Looper Message 之间的那些事
- android之handler messagequene looper threadlocal 之间的详细解读
- Android基于Handler、Looper、MessageQueue、ThreadLocal的跨线程通信
- Android 消息机制---Handler,Looper,MessageQueue,ThreadLocal
- Handler、Looper、ThreadLocal 、Values
- Looper,Handler,Message Queue和线程之间的那些事
- Android开发:Handler、Looper、MessageQueue
- 理解Android消息处理系统 -- Handler & Message & Looper & ThreadLocal
- android Handler Message MessageQueue Looper ThreadLocal源码解读
- Handler、Looper、ThreadLocal、MessageQueue、Message
- Android开发--多线程中的Handler机制/Looper的介绍
- Android开发之Handler和Looper的关系
- Android开发中Handler、Looper、MessageQueue的原理
- Android笔记-MultiThreading in Android(1)-Thread,Looper,Handler,Message,MessageQueue之间的关系
- 主机的IP配置
- python mysql安装使用
- Freemark的介绍
- Spring 源码中的错误
- Android中的枚举
- Android开发笔记1:Handler、Looper、ThreadLocal的那些事
- vector类的实现
- 领域专用语言开源框架Xtext 2.0 发布了
- 硬盘下安装CentOS \Fedora
- Oracle中实现javascript中的Eval函数计算效果
- android 之 01
- iOS 本地化应用程序汇总 国际化
- 应用程序(xx)与系统不兼容,是否继续安装?
- datecontrol