Thread、Handler与HandlerThread
来源:互联网 发布:论文meta分析数据 编辑:程序博客网 时间:2024/04/27 04:21
今天在看Android源码的时候,看到了大量Handler的应用,和我以前开发APP的时候使用Handler的方法不太一样,所以花了一些时间来研究Handler。这里简单的记录一下。
Handler、Thread与Loop
一个线程(Thread)“可以”存在一个消息队列(MessageQueue)和一个消息循环(MessageQueue)。但是在线程创建的时候,这两个东西是不存在的。需要用Looper.prepare()来创建消息队列,用Looper.loop()来启动消息的循环。请看下面的这个例子。
public class LooperThread extends Thread { public Handler mHandler; public void run(){ Looper.prepare(); // 创建消息队列。 mHandler = new Handler(){ @Override public void handlerMessage(Message msg){} }; Looper.loop(); // 启动消息循环。这个要在run()函数的最后调用。 }}
这个例子是在一个自定义的线程中创建了Looper并让消息队列循环跑起来。那么这样一个有Looper和MessageQueue的线程和Handler的关系是怎么样的呢?在Handler初始化的时候,如果使用的是无参的构造函数,那么它将获取当前线程的Looper和MessageQueue,如果初始化的时候传入了Looper,那么Handler将获取这个Looper以及对应的MessageQueue。换句话说,传入的是哪个线程的Looper,Handler就属于哪个线程。所以一个Handler只能属于一个Thread。
另外一句话就是一个线程却可以拥有多个Handler。这句话我在很多个地方都看到了,但是因为没有仔细的去分析源代码,所以没有找到这句话的来源,但是我可以给出一个例子,说明一个线程是可以拥有多个Handler的,在消息的传递过程中不会乱。例子如下:
// 发送消息一般有如下两种方法 Message msg = new Message();msg.what = 1;handler.sendMessage(msg);Message msg = handler.obtainMessage();msg.what = 1;msg.sendToTarget();
很明显,第一种方法产生的msg将传递给调用sendMessage()方法的handler,第二种方法产生的msg将传递给调用obtainMessage()方法的handler。
说一句题外话,在Android APP开发中,因为更新UI只能在主线程中进行,所以经常会在主线程中定义Handler,子线程通过向Handler发送消息,由Handler对象的handleMessage()函数来更新UI。在这种情况下,并不需要显式地调用Looper.prepare()和Looper.loop()。这其中的原因就是在UI的ActivityThread中已经调用过了这两个函数,也就是说,每一个APP的主线程都默认定义好了Looper和MessageQueue,所以直接用就好了。有兴趣的朋友可以研究一下ActivityThread.java这个文件。
Handler的构造函数
Android源码中Handler的构造函数有好几个,分别如下:
public Handler() { this(null, false);}public Handler(Callback callback) { this(callback, false);}public Handler(Looper looper) { this(looper, null, false);}public Handler(Looper looper, Callback callback) { this(looper, callback, false);}/** * @hide */public Handler(boolean async) { this(null, async);}/** * @hide */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(); if (mLooper == null) { throw new RuntimeException( "Can't create handler inside thread that has not called Looper.prepare()"); } mQueue = mLooper.mQueue; mCallback = callback; mAsynchronous = async;}/** * @hide */public Handler(Looper looper, Callback callback, boolean async) { mLooper = looper; mQueue = looper.mQueue; mCallback = callback; mAsynchronous = async;}
我抽几个常用的简单分析一下。首先是默认构造函数:
public Handler() { this(null, false);}
可见它实际上将调用下面的构造函数:
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()"); } mQueue = mLooper.mQueue; // 获取当前线程的MessageQueue。 mCallback = callback; mAsynchronous = async;}
首先获取当前线程的Looper,然后通过这个Looper获取当前线程的MessageQueue。这样,线程的Looper和MessageQueue将交由Handler处理。
另外一个常用的构造函数如下:
public Handler(Looper looper, Callback callback) { this(looper, callback, false);}
它将调用的构造函数如下:
public Handler(Looper looper, Callback callback, boolean async) { mLooper = looper; mQueue = looper.mQueue; mCallback = callback; mAsynchronous = async;}
这里的Handler对象将绑定传入的Looper并通过传入的Looper对象获取其MessageQueue。
HandlerThread
HandlerThread是谷歌制造出来专为异步处理各种消息的线程,借助于它,我们可以非常方便的设计出异步处理程序。为什么方便?因为它默认的run()函数里已经构建好了Looper和MessageQueue。
public void run() { mTid = Process.myTid(); Looper.prepare(); // 就是这里 synchronized (this) { mLooper = Looper.myLooper(); notifyAll(); } Process.setThreadPriority(mPriority); onLooperPrepared(); Looper.loop(); // 还有这里 mTid = -1;}
然后通过它的getLooper()方法即可获得这个线程的Looper。
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; // 就是这里}
然后绑定Handler与Looper就可以了。
下面,我给出一个典型的HandlerThread应用。
// 首先实例化一个MyHandlerThread。MyHandlerThread mHandlerThread = new MyHandlerThread("Timothy");// 让这个HandlerThread跑起来。mHandlerThread.start();// 获取HandlerThread的Looper,通过它将Handler与HandlerThread绑定起来。注意这里用的构造函数。Handler mHandler = new Handler(mHandlerThread.getLooper(), mHandlerThread);// 注意这里的MyHandlerThread实现了Callback接口。private class MyHandlerThread extends HandlerThread implements Callback{ public MyHandlerThread(String name){ super(name); } @Override public boolean handleMessage(Message msg){ return true; }}
这里要着重讲的是Handler为什么要选用上面的这个构造函数。这个构造函数的第一个参数好理解,就是将Handler与传进去的Looper绑定。那第二个参数呢?我们使用HandlerThread想要得到的效果是发送给Handler的消息将在线程中处理,即调用MyHandlerThread中的handleMessage()函数。我们可以看一下Handler类中的dispatchMessage()函数。这个函数就是分发Message的。
public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); }}private static void handleCallback(Message message) { message.callback.run();}
这里首先检查msg是不是runable(为什么会是runable,后面解释)。这个分支在这里不会跑。那么就进入了else分支。首先检查mCallback是不是为空。这个查看我们是用的构造函数(就是介绍的第二个构造函数):
public Handler(Looper looper, Callback callback) { this(looper, callback, false);}public Handler(Looper looper, Callback callback, boolean async) { mLooper = looper; mQueue = looper.mQueue; mCallback = callback; mAsynchronous = async;}
可见,mCallback就是构造函数的第二个参数。在我们的这个例子中,这个mCallback当然不是空,所以就会执行mCallback的handleMessage(),也就是我们MyHandlerThread的handleMessage()函数。我们的目的就达到了。
补充一句,如果mCallback为空,或者mCallback不为空,但是我们在MyHandlerThread的handleMessage()中返回的是false,就将调用这个handler对象的handleMessage()函数。后一种情况跟Android APP开发中的onKeyDown()函数的处理方法类似。
下面回过头来解释一下第一个if判断分支的作用。
我们知道,Handler除了传递Message这个作用外,还有另外一系列的方法,例如下面这几个:
public final boolean post(Runnable r);public final boolean postDelayed(Runnable r, long delayMillis);……
这几个函数的作用也是异步处理,不过传递的是Runable。当某些函数需要立即返回,但是这些函数的实际操作又要耗时时,就会调用这些函数,让耗时操作在未来的某个时间进行,同时立即返回。
我们这里跟踪一下post()函数的实现:
public final boolean post(Runnable r){ return sendMessageDelayed(getPostMessage(r), 0);}// 这里创建了一个Message,并且把Runable对象存储在了它的callback属性里面。private static Message getPostMessage(Runnable r) { Message m = Message.obtain(); m.callback = r; return m;}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; }// 这里将创建的Message对象加入到MessageQueue里面。 return enqueueMessage(queue, msg, uptimeMillis);}
post()函数的调用过程就是新建一个Message对象,将Runnable对象存储在这个Message对象的callback字段里面,然后将Message对象加入MessageQueue。所以当dispatch的时候,会检查当前Message的callback是不是为空,即是不是由Runable创建的,如果是Runnable对象,就运行之(handleCallback()函数)。
- Thread、Handler与HandlerThread
- Thread、Handler与HandlerThread、Handler使用
- Thread、Handler与HandlerThread、Handler使用
- Thread、Handler与HandlerThread、Handler使用
- Thread、Handler与HandlerThread、Handler使用
- Thread、Handler与HandlerThread、Handler使用
- android中handlerthread与handler + thread区别
- HandlerThread,Handler,Thread使用方法
- HandlerThread,Handler,Thread使用方法
- HandlerThread,Handler,Thread使用方法
- HandlerThread,Handler,Thread使用方法
- HandlerThread,Handler,Thread使用方法
- HandlerThread,Handler,Thread使用方法
- HandlerThread,Handler,Thread使用方法
- Handler, thread, handlerthread
- HandlerThread,Handler,Thread使用方法
- HandlerThread,Handler,Thread使用方法
- HandlerThread,Handler,Thread使用方法
- 古堡算式
- 21.Oracle数据库SQL开发之 连接条件和链接类型
- OC与Swift混编
- Scala中对List进行高效的排序和倒排序
- 22.Oracle数据库SQL开发之 SQL92语法执行连接
- Thread、Handler与HandlerThread
- JavaScript语法
- <hx>标签,为你的网页添加标题
- cadence设置不同网络颜色
- 创建角色名如何在中英文混排的情况下精确限制长度
- Fragment输入状态丢失的修复:
- js学习总结2
- C++11新特性之std::function
- PHP(1)起航