转载请注明出处:http://blog.csdn.net/vnanyesheshou/article/details/75073307

对于Handler不太懂的可以参考我的这两篇文章:
Android Handler的基本使用
深入理解Handler、Looper、Messagequeue
这篇主要说一下HandlerThread的使用方法,及分析下其源码。


1 HandlerThread

HandlerThread类介绍

Handy class for starting a new thread that has a looper. The looper can then be used to create handler classes. Note that start() must still be called.

HandlerThread是Android API提供的一个方便、便捷的类,使用它我们可以快速的创建一个带有Looper的线程。Looper可以用来创建Handler实例。注意:start()仍然必须被调用。

如下是HandlerThread使用的demo。

package com.zpengyong.hand;import android.app.Activity;import android.os.Bundle;import android.os.Handler;import android.os.HandlerThread;import android.os.Looper;import android.os.Message;import android.util.Log;import android.view.View;import android.view.View.OnClickListener;import android.widget.Button;import android.widget.TextView;public class MainActivity extends Activity {    private final static String TAG = "MainActivity";    private Button mGet;    private TextView mResult;    protected final int MSG_GET = 1;    protected final int MSG_RESULT = 2;    private HandlerThread mHandlerThread;    //子线程中的Handler实例。    private Handler mSubThreadHandler;    //与Ui线程绑定的Handler实例。    private Handler mUiHandler = new Handler(){        public void handleMessage(Message msg) {            Log.i(TAG, "mUiHandler handleMessage thread:"+Thread.currentThread());            switch (msg.what) {            case MSG_RESULT:                mResult.setText((String)msg.obj);                break;            default:                break;            }        };    };    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        Log.i(TAG, "onCreate thread:"+Thread.currentThread());        mGet = (Button) findViewById(R.id.get);        mGet.setOnClickListener(new OnClickListener() {            @Override            public void onClick(View v) {                mSubThreadHandler.sendEmptyMessage(MSG_GET);            }        });        mResult = (TextView) findViewById(R.id.result);        initHandlerThraed();    }    private void initHandlerThraed() {        //创建HandlerThread实例        mHandlerThread = new HandlerThread("handler_thread");        //开始运行线程        mHandlerThread.start();        //获取HandlerThread线程中的Looper实例        Looper loop = mHandlerThread.getLooper();        //创建Handler与该线程绑定。        mSubThreadHandler = new Handler(loop){            public void handleMessage(Message msg) {                Log.i(TAG, "mSubThreadHandler handleMessage thread:"+Thread.currentThread());                switch(msg.what){                case MSG_GET:                    try { //模拟延时处理                        Thread.sleep(1000);                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                    double number = Math.random();                    String result = "number:"+number;                    //向ui线程发送消息,更新ui。                    Message message = new Message();                    message.what = MSG_RESULT;                    message.obj = result;                    mUiHandler.sendMessage(message);                    break;                default:                    break;                }            };        };    }    @Override    protected void onDestroy() {        super.onDestroy();        Log.i(TAG, "onDestroy");        //退出HandlerThread的Looper循环。        mHandlerThread.quit();    }}

上述代码比较简单,功能也比较简单,可以在此基础上进行扩展。
在Actvitiy创建的时候调用initHandlerThraed()函数:

  1. 创建HandlerThread线程
  2. 运行线程
  3. 获取HandlerThread线程中的Looper实例
  4. 通过Looper实例创建Handler实例,从而使mSubThreadHandler与该线程连接到一起。

多次点击按钮,打印信息如下所示:

07-13 05:15:07.662: I/MainActivity(1472): onCreate thread:Thread[main,5,main]07-13 05:15:45.382: I/MainActivity(1472): mSubThreadHandler handleMessage thread:Thread[handler_thread,5,main]07-13 05:15:46.402: I/MainActivity(1472): mUiHandler handleMessage thread:Thread[main,5,main]07-13 05:15:46.412: I/MainActivity(1472): mSubThreadHandler handleMessage thread:Thread[handler_thread,5,main]07-13 05:15:47.412: I/MainActivity(1472): mUiHandler handleMessage thread:Thread[main,5,main].....

点击按钮,向mSubThreadHandler发送消息,mSubThreadHandler中接收到消息进行处理,由打印可知mSubThreadHandler的handleMessage方法运行在子线程中。
模拟耗时操作,生成随机数,然后向主线程中(mUiHandler)发送消息(Message)。

mUiHandler的handleMessage方法运行在主线程,可以用来更新Ui界面。

Activity销毁的时候,调用mHandlerThread.quit(),退出HandlerThread的Looper循环。

效果图如下:


2 HandlerThread源码分析

源码路径路径:frameworks/base/core/java/android/os/HandlerThread.java

先看下HandlerThread的构造方法。

public class HandlerThread extends Thread {    int mPriority;    int mTid = -1;    Looper mLooper;    //@param name 线程名    public HandlerThread(String name) {        super(name);        mPriority = Process.THREAD_PRIORITY_DEFAULT;    }    /**     * Constructs a HandlerThread.     * @param name     * @param priority The priority to run the thread at. The value supplied must be from      * {@link android.os.Process} and not from java.lang.Thread.     */    public HandlerThread(String name, int priority) {        super(name);        mPriority = priority;    }    。。。。

HandlerThread是Thread(线程)的子类。创建一个HandlerThread实例,也就是创建了一个特殊的线程实例。
HandlerThread提供了两个构造方法:

  • HandlerThread(String name) 参数为线程名称,线程优先级为Process.THREAD_PRIORITY_DEFAULT。
  • HandlerThread(String name, int priority),name为线程名称,priority为设置的线程优先级。

我们知道线程需要通过start()方法来运行线程,HandlerThread也是这样的。接着看下线程运行的run()方法。

/** * Call back method that can be explicitly overridden if needed to execute some * setup before Looper loops. */protected void onLooperPrepared() {}@Overridepublic void run() {    //获取进程id    mTid = Process.myTid();    //创建Looper实例    Looper.prepare();    synchronized (this) {        //获取当前线程的Looper实例        mLooper = Looper.myLooper();        notifyAll();    }    //设置线程优先级    Process.setThreadPriority(mPriority);    onLooperPrepared();    //开始循环    Looper.loop();    mTid = -1;}

由run方法可知HandlerThrea线程运行创建了Looper实例,并开启了Looper循环,循环从消息队列中获取消息并给Handler进行处理。对于Looper不太明白的可以参考这篇深入理解Handler、Looper、Messagequeue

onLooperPrepared()在Looper循环之前调用,如果需要在Looper循环之前执行一些设置,可以显式覆盖此方法。

接着看获取Looper实例

//获取HandlerThread线程中的Looper实例Looper loop = mHandlerThread.getLooper();

对应源码:

//此方法返回与此线程关联的Looper。 如果此线程未启动或由于任何原因isAlive()返回false,此方法将返回null。public Looper getLooper() {    if (!isAlive()) {        return null;    }    // 如果这个线程已经启动,将会被阻塞,直到mLooper被初始化为止。    synchronized (this) {        while (isAlive() && mLooper == null) {            try {                wait();            } catch (InterruptedException e) {            }        }    }    return mLooper;}

mHandlerThread.getLooper()获取与该线程绑定的Looper实例。mLooper是在HandlerThread的run()方法中赋值的(也就是在子线程中),getLooper是我们在主线程中调用,该方法会阻塞直到mLooper赋值。

然后demo中通过该looper实例创建Handler

//创建Handler与该线程绑定。mSubThreadHandler = new Handler(loop)

你可能会好奇为什么要这样长久Handler而不是“new Handler()“这样呢?因为我们要创建的Handler要与子线程绑定到一起,要处理子线程中的消息,所以要通过子线程中的looper(有线程对应的消息队列)实例创建Handler。这样通过mSubThreadHandler发送的消息会添加到子线程中的消息队列中,然后Looper实例消息进行分发,交给mSubThreadHandler进行处理。

HandlerThread提供的线程退出方法:

public boolean quit() {    Looper looper = getLooper();    if (looper != null) {        looper.quit();        return true;    }    return false;}public boolean quitSafely() {    Looper looper = getLooper();    if (looper != null) {        looper.quitSafely();        return true;    }    return false;}

quit和quitSafely都是退出HandlerThread的消息循环。其分别调用Looper的quit和quitSafely方法。
quit方法会将消息队列中的所有消息移除(延迟消息和非延迟消息)。
quitSafely会将消息队列所有的延迟消息移除,非延迟消息派发出去让Handler去处理。quitSafely相比于quit方法安全之处在于清空消息之前会派发所有的非延迟消息

HandlerThread适合处理本地IO读写操作(数据库,文件),因为本地IO操作大多数的耗时属于毫秒级别,对于单线程 + 异步队列的形式 不会产生较大的阻塞。而网络操作相对比较耗时,容易阻塞后面的请求,因此在这个HandlerThread中不适合加入网络操作。

至此HandlerThread就说完了。有什么问题欢迎大家指正、交流。

DEMO下载:http://www.demodashi.com/demo/10628.html

更多相关文章

  1. android报The content of the adapter has changed but ListView
  2. Android实现内存中数据保存到sdcard的方法
  3. Android(安卓)Toast 总结
  4. Android(安卓)反序列化异常EOFException的解决
  5. Android(安卓)-- 基础
  6. Android之ksoap2-android详解与调用天气预报Webservice完整实例
  7. 关于android组播通讯只能收到本机消息的问题
  8. Android(安卓)Audio 框架简读
  9. Android文件上传与下载

随机推荐

  1. Android(安卓)获取手机SIM卡运营商
  2. android linux工具移植
  3. 网络连接ConnectivityManager
  4. Android(安卓)模拟器支持的分辨率
  5. android 布局
  6. android Preference ListPreference Edit
  7. android一些核心功能程序代码
  8. Android(安卓)studio 常用的插件
  9. Android(安卓)C/CPP log
  10. 优秀博文