如果已经理解了Android的消息机制(Handler、Looper、Message、MessageQueue),再来看HandlerThread就很容易了,参考如下:
http://blog.csdn.net/kitty_landon/article/details/53410183
源码解析
最直观的方法就是分析源码,先把源码贴出来。
/**
* 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可以创建拥有Looper的线程,这个Looper能够创建Handler类
*/
public class HandlerThread extends Thread {
int mPriority;//线程优先级
int mTid = -1;
Looper mLooper;//当前线程持有的Looper对象
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;
}
/**
* Call back method that can be explicitly overridden if needed to execute some
* setup before Looper loops.可以重写,但是在Looper循环之前。
*/
protected void onLooperPrepared() {
}
@Override
public void run() {//创建HandlerThread对象后,必须调用start()方法,调用start()方法后,表示线程启动了,也就会调用线程的run()方法;
mTid = Process.myTid();
Looper.prepare();//创建Looper对象,并绑定当前线程
synchronized (this) {
mLooper = Looper.myLooper();//获取Looper对象
notifyAll();//唤醒等待线程
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();//循环
mTid = -1;
}
/**
* This method returns the Looper associated with this thread. 返回与该线程相关联的Looper对象。If this thread not been started
* or for any reason is isAlive() returns false, this method will return null. (如果线程没有开启,或者isAlive()返回false,getLooper()返
回null)。If this thread
* has been started, this method will block until the looper has been initialized. 开启了线程,这个方法将会阻塞,直到Looper初始化
* @return The 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;
}
/**
* Quits the handler thread's looper.
* <p>
* Causes the handler thread's looper to terminate without processing any
* more messages in the message queue.
* </p><p>
* Any attempt to post messages to the queue after the looper is asked to quit will fail.
* For example, the {@link Handler#sendMessage(Message)} method will return false.
* </p><p class="note">
* Using this method may be unsafe because some messages may not be delivered
* before the looper terminates. Consider using {@link #quitSafely} instead to ensure
* that all pending work is completed in an orderly manner.
* </p>
*
* @return True if the looper looper has been asked to quit or false if the
* thread had not yet started running.
*
* @see #quitSafely
*/
public boolean quit() {
Looper looper = getLooper();
if (looper != null) {
looper.quit();
return true;
}
return false;
}
/**
* Quits the handler thread's looper safely.
* <p>
* Causes the handler thread's looper to terminate as soon as all remaining messages
* in the message queue that are already due to be delivered have been handled.
* Pending delayed messages with due times in the future will not be delivered.
* </p><p>
* Any attempt to post messages to the queue after the looper is asked to quit will fail.
* For example, the {@link Handler#sendMessage(Message)} method will return false.
* </p><p>
* If the thread has not been started or has finished (that is if
* {@link #getLooper} returns null), then false is returned.
* Otherwise the looper is asked to quit and true is returned.
* </p>
*
* @return True if the looper looper has been asked to quit or false if the
* thread had not yet started running.
*/
public boolean quitSafely() {
Looper looper = getLooper();
if (looper != null) {
looper.quitSafely();
return true;
}
return false;
}
/**
* Returns the identifier of this thread. See Process.myTid().
*/
public int getThreadId() {
return mTid;
}
}
从getLooper()方法实现源码上可以看出外部在通过getLooper()方法获取Looper对象时,会先判断当前线程是否启动了,如果线程已经启动,那么将会进入同步语句并判断Looper是否为null,为null则代表Looper对象还没有被赋值,也就是还没被创建,此时当前调用线程进入等待状态,知道Looper对象被创建并通过notifyAll()方法唤醒等待线程,最后才返回Looper对象。之所以需要等待唤醒机制,是因为Looper的创建是在子线程中执行的,而调用getLooper方法则是在主线程进行的,这样我们就无法保障我们在调用getLooper方法时Looper已经被创建,到这里我们也就明白了在获取mLooper对象时会存在一个同步的问题,只有当线程创建成功并且Looper对象也创建成功之后才能获得mLooper的值,HandlerThread内部则通过等待唤醒机制解决了同步问题。
从源码可以看出当我们调用quit方法时,其内部实际上是调用Looper的quit方法而最终执行的则是MessageQueue中的removeAllMessagesLocked方法(Handler消息机制知识点),该方法主要是把MessageQueue消息池中所有的消息全部清空,无论是延迟消息(延迟消息是指通过sendMessageDelayed或通过postDelayed等方法发送)还是非延迟消息。
从源码中我们可以看出HandlerThread有几个特点:
(1)、HandlerThread本质上是一个线程类,它继承了Thread;
(2)、HandlerThread有自己的内部Looper对象,可以进行loop循环;
(3)、通过获取HandlerThread的Looper对象传递给Handler对象,可以在handleMessage()方法中执行异步任务;
(4)、创建HandlerThread后必须先调用HandlerThread.start()方法,Thread会先调用run()方法,创建Looper对象。
HandlerThread常规使用步骤
方案一:利用Handler(Looper looper, Callback callback)
1、创建HandlerThread实例对象
HandlerThread mMainJobThread = new HandlerThread("qscan");
传入参数的作用主要是标记当前线程的名字,可以是任意字符串。
2、启动HandlerThread线程
mMainJobThread.start();
到此,我们创建完HandlerThread并启动了线程。那么我们怎么将一个耗时的异步任务投放到HandlerThread线程中去执行呢?接下来看下面步骤:
3、构建循环消息处理机制
/**
* 该callback运行于子线程
*/
class ChildCallback implements Handler.Callback {
@Override
public boolean handleMessage(Message msg) {
//在子线程中进行相应的网络请求
//通知主线程去更新UI
mUIHandler.sendMessage(msg1);
return false;
}
}
4、构建异步Handler
Handler mMainJobHandler = new Handler(mMainJobThread.getLooper(), new ChildCallback());
第3步和第4步是构建一个可以用于异步操作的handler,并将前面创建的HandlerThread的Looper对象以及Callback接口类作为参数传递给当前的handler,这样当前的异步handler就拥有了HandlerThread的Looper对象,由于HandlerThread本身是异步线程,因此Looper也与异步线程绑定,从而handlerMessage方法也就可以异步处理耗时任务了,这样我们的Looper+Handler+MessageQueue+Thread异步循环机制构建完成,来看看一个完整的使用案例。
方案二:利用Handler(Looper looper)
步骤一和步骤二是相同的;
3、构建循环消息处理机制
private class MainJobHandler extends Handler {
public MainJobHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
Log.e(TAG, "MainJobHandler() -> msg.what = " + msg.what);
......
}
}
4、构建异步Handler
MainJobHandler mMainJobHandler = new MainJobHandler(mMainJobThread.getLooper());
使用案例
public class HandlerThreadActivity extends Activity {
/**
* 图片地址集合
*/
private String url[]={
"https://img-blog.csdn.net/20160903083245762",
"https://img-blog.csdn.net/20160903083252184",
"https://img-blog.csdn.net/20160903083257871",
"https://img-blog.csdn.net/20160903083257871",
"https://img-blog.csdn.net/20160903083311972",
"https://img-blog.csdn.net/20160903083319668",
"https://img-blog.csdn.net/20160903083326871"
};
private ImageView imageView;
private Handler mUIHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
LogUtils.e("次数:"+msg.what);
ImageModel model = (ImageModel) msg.obj;
imageView.setImageBitmap(model.bitmap);
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_handler_thread);
imageView= (ImageView) findViewById(R.id.image);
//创建异步HandlerThread
HandlerThread handlerThread = new HandlerThread("downloadImage");
//必须先开启线程
handlerThread.start();
//子线程Handler
Handler childHandler = new Handler(handlerThread.getLooper(),new ChildCallback());
for(int i=0;i<7;i++){
//每个1秒去更新图片
childHandler.sendEmptyMessageDelayed(i,1000*i);
}
}
/**
* 该callback运行于子线程
*/
class ChildCallback implements Handler.Callback {
@Override
public boolean handleMessage(Message msg) {
//在子线程中进行网络请求
Bitmap bitmap=downloadUrlBitmap(url[msg.what]);
ImageModel imageModel=new ImageModel();
imageModel.bitmap=bitmap;
imageModel.url=url[msg.what];
Message msg1 = new Message();
msg1.what = msg.what;
msg1.obj =imageModel;
//通知主线程去更新UI
mUIHandler.sendMessage(msg1);
return false;
}
}
private Bitmap downloadUrlBitmap(String urlString) {
HttpURLConnection urlConnection = null;
BufferedInputStream in = null;
Bitmap bitmap=null;
try {
final URL url = new URL(urlString);
urlConnection = (HttpURLConnection) url.openConnection();
in = new BufferedInputStream(urlConnection.getInputStream(), 8 * 1024);
bitmap=BitmapFactory.decodeStream(in);
} catch (final IOException e) {
e.printStackTrace();
} finally {
if (urlConnection != null) {
urlConnection.disconnect();
}
try {
if (in != null) {
in.close();
}
} catch (final IOException e) {
e.printStackTrace();
}
}
return bitmap;
}
}
在这个案例中,我们创建了两个Handler,一个用于更新UI线程的mUIHandler和一个用于异步下载图片的childHandler。最终的结果是childHandler会每个隔1秒钟通过sendEmptyMessageDelayed方法去通知ChildCallback的回调函数handleMessage方法去下载图片并告诉mUIHandler去更新UI界面,以上便是HandlerThread常规使用。
实际上在android比较典型的应用是IntentService。