HandlerThread详解

1 HandlerThread基本原理

  HandlerThread继承自Thread,它是一种可以使用Handler的Thread。它的实现很简单,就是在run方法中通过Looper.prepare()来创建消息队列,并通过Looper.loop()来开启消息循环。这样,我们就可以直接在HandlerThread中创建Handler了。HandlerThread的run方法如下所示:

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

  既然HandlerThread中已经有了消息循环,那么我们就可以在HandlerThread类或其子类中直接创建Handler对象,但是我们要记住一点:如果我们需要创建与该HandlerThread线程相关联的Handler的话,我们要使用Handler(Looper looper)构造方法,这样我们所创建的Handler对象才会与当前线程的消息循环相关联。在HandlerThread中,我们可以通过getLooper()方法获得Looper实例。

  从HandlerThread的实现上来看,它和普通Thread有显著不同,普通Thread主要在run方法中执行耗时任务,而HandlerThread在内部创建了消息队列,外界需要通过Handler的消息方式来通知HandlerThread执行一个具体任务。通常,一个普通的Thread线程也可以成为Looper线程,我们只需要为其创建消息队列并开启消息循环即可。看如下实现代码:

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

我们可以根据不同应用场景选择不同的实现方式,不过既然Android已经提供了HandlerThread类,那我们在开发过程中可能会更倾向于使用该类完成耗时操作。

2 示例程序

  我们将通过一个简单示例程序来说明HandlerThread的用法。本示例程序中,我们向HandlerThread发送消息,然后HandlerThread返回该消息并显示到TextView上,在这个过程中我们通过sleep来模拟耗时操作。我们将创建一个继承自HandlerThread的类:CustomHandlerThread,

 public class CustomHandlerThread extends HandlerThread {
private static final String TAG = "CustomHandlerThread";
private static final int MSG_WHAT = 0x11;
private Handler mResponseHandler;
private Handler mHandler;
private Callback mCallback;
public CustomHandlerThread(Handler responseHandler, Callback callback){
super(TAG);
mHandler = new Handler();
mResponseHandler = responseHandler;
mCallback = callback;
} public void enqueTask(String str, TextView textView){
Log.i(TAG, "receive a str: " + str);
mHandler.obtainMessage(MSG_WHAT, str).sendToTarget();
}
public void prepareHandler(){
mHandler = new Handler(getLooper()){
@Override
public void handleMessage(final Message msg) {
try{
TimeUnit.SECONDS.sleep(2);
final String result = (String)msg.obj;
mResponseHandler.post(new Runnable() {
@Override
public void run() {
mCallback.onResult(result);
}
});
}catch (InterruptedException ie){
ie.printStackTrace();
}
}
};
} public interface Callback{
public void onResult(String result);
}
public void removeMsg(){
mHandler.removeMessages(MSG_WHAT);
} }

  我们先看enqueTask方法,该方法很简单,我们仅用它来接收从外部传来的参数(准确的说是消息内容),并且通过当前线程的Handler将消息发送到当前线程消息队列中,对该消息的处理是在prepareHandler()方法中完成的。在prepareHandler方法中,我们创建Handler实例,并且与当前线程的消息队列相关联,这通过Handler(Looper looper)构造方法完成。mResponseHandler.post方法会将Runnable对象添加到主线程的消息队列,该Runnable对象将会在该mResponseHandler所属的线程中执行,由于mResponseHandler是从主线程传过来的(稍后我们会看到具体实现),因此Runnable将会运行在主线程中。run方法中我们通过回调接口来传递结果。下面我们看下MainActivity中的处理:

 public class MainActivity extends Activity implements CustomHandlerThread.Callback{
private TextView mTextView; private CustomHandlerThread mCustomHandlerThread;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTextView = (TextView)findViewById(R.id.textView); mCustomHandlerThread = new CustomHandlerThread(new Handler(), this);
mCustomHandlerThread.start();
mCustomHandlerThread.prepareHandler();
for(int i = 0; i < 10; i++){
mCustomHandlerThread.enqueTask("string"+i);
}
} @Override
public void onResult(String result) {
mTextView.setText(result);
} @Override
protected void onDestroy() {
super.onDestroy();
mCustomHandlerThread.removeMsg();
mCustomHandlerThread.quit();
}
}

上面代码很简单,我们创建CustomHandlerThread并传入Handler对象,该Handler对象是在主线程中创建的,因此与主线程消息队列相关联,创建HandlerThread对象后必须要调用start方法,此外,在调用enqueTask之前必须先调用prepareHandler方法,以免导致空指针异常(Handler还没创建?怎么能向消息队列发送消息呢?)。最后要注意的是,当Activity退出时,我们一定要通过quit方法结束HandlerThread的执行。

Android之HandlerThread的更多相关文章

  1. Android 开发 HandlerThread详解 转载

    转载请注明出处:http://blog.csdn.net/vnanyesheshou/article/details/75073307 对于Handler不太懂的可以参考我的这两篇文章: Androi ...

  2. Android开发——HandlerThread以及IntentService详解

    .HandlerThread Android API提供了HandlerThread来创建线程.官网的解释是: //Handy class for starting a new thread that ...

  3. Android中HandlerThread的使用及源代码解析

    关于Hanlder的基本使用能够參见博文<Android中Handler的使用>,假设想了解Handler.Looper.Thread等的相互关系以及内部实现原理能够參见博文<深入源 ...

  4. Android多线程—HandlerThread解析

    一.HandlerThread作用 1.实现多线程:在工作线程之后执行任务(比如一些耗时任务) 2.异步通信.消息传递:实现工作线程与主线程(UI线程)之间的通信,即将工作线程的执行结果传递给主线程, ...

  5. Android(八) HandlerThread

    1.Looper Looper used to run a message loop for a thread. Threads by default do not have a message lo ...

  6. Android HandlerThread 总结使用

    转载请标明出处:http://www.cnblogs.com/zhaoyanjun/p/6062880.html 本文出自[赵彦军的博客] 前言 以前我在 [Android Handler.Loop ...

  7. Android HandlerThread 的使用及其Demo (转)

    转自http://www.cnblogs.com/hnrainll/p/3597246.html 介绍 首先我们来看看为什么我们要使用HandlerThread?在我们的应用程序当中为了实现同时完成多 ...

  8. 【Android】用HandlerThread模拟AsyncTask功能(ThreadTask)

    前言 AsyncTask是个好东西,能处理绝大多数应用线程和更新UI的任务,由于其内部使用了静态线程池,如果你有一堆异步任务(例如全局定时更新数据.同一个Activity中多个AsyncTask同时执 ...

  9. Android HandlerThread 的使用及其Demo

    今天我们一起来学习下一个Android中比较简单的类HandlerThread,虽然它的初始化有点小麻烦. 介绍 首先我们来看看为什么我们要使用HandlerThread?在我们的应用程序当中为了实现 ...

随机推荐

  1. WCF基于MSMQ的事件代理服务

    前言 公司目前楼主负责的项目正在改版升级,对之前的服务也在作调整,项目里有个操作日志的模块,就决定把日志单独提取出来,做个日志服务,所以就有了这篇文章 正文 MSMQ作为消息队列,B/S项目调用日志服 ...

  2. [Usaco2008 Nov]Guarding the Farm 保卫牧场[DFS]

    Description The farm has many hills upon which Farmer John would like to place guards to ensure the ...

  3. linux下telnet mysql的3306断口,提示Can't connect to MySQL server on localhost (110)

    新购买的阿里云ECS服务器,食用lnmp环境,安装完毕后,telnet localhost 3306提示Can't connect to MySQL server on localhost (110) ...

  4. WINCE 电池状态(C#)

    WINCE 电池状态(C#) 分类:             电量              2013-04-18 12:08     397人阅读     评论(1)     收藏     举报   ...

  5. JavaScript 实现文本编辑器

    JavaScript 实现文本编辑器 最近,我需要做一个非常基本的网页内容编辑功能.我不想使用 iframe ,我也不想要一个功能特别多的复杂编辑器,只需要很基本的内容编辑功能,例如粗体,斜体,列表, ...

  6. 使用Emacs:生存篇

    使用Emacs:生存篇 vim和Emacs都是很强大的编辑器.所以,入门有一定难度.这里不谈vim,谈Emacs下的生存--第一次使用Emacs时的使用. 1.emacs的安装: 在Fedora下: ...

  7. continue与break

    1.continue语句,1至20内奇数累加和 #include<iostream> using namespace std; void main(){ int i=0; int sum= ...

  8. 当ArcGIS10.2遇到Teradata

                                    随着计算机技术的不断发展,GIS技术也紧跟IT技术的热潮,从三维技术.到移动技术,从大数据技术到云计算技术,只要IT有的新技术,Esri ...

  9. jvm回收对象

    jvm在判断对象死亡之前需要判断对象是否可到达,方法有引用计数算法和可达性分析算法,jvm采用的是后者.首先来了解一下这两种算法. 引用计数算法: 算法定义 为每个对象增加一个字段记录被引用的次数,并 ...

  10. idea下git版本回退

    首先选中项目名,然后 ,show history, copy你想要回退版本的reversion number, ,然后在branches里check out你想要回退的版本