Handler 原理分析和使用之HandlerThread

前面已经提到过Handler的原理以及Handler的三种用法。这里做一个非常简单的一个总结:

  • Handler 是跨线程的Message处理。负责把Message推送到MessageQueue和处理。
  • Looper 用来轮询MessageQueue,获取Message 发送给指定的Handler进行处理。
  • Looper 需要和线程绑定,绑定那个线程,Handler就会在那个线程处理Message

前两篇文章使用Handler处理的场景是:主线程(UI线程)被子线程更新。即使用主线程的Handler和Looper,在子线程中发Message。然后主线程处理 handlerMessage。

-----------------------------------------------------------------------------------------

下面反过来说,如何从UI线程发消息,让子线程处理。

最为通常的做法是:new Thread().start。起一个线程去完成一个任务,任务完成线程就可以自毙了。当然了如果不需要子线程返回结果,而且只有一个线程,那么这是最简单的了。

另一种方法是SyncTask。实例如下:

 import android.os.AsyncTask;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView; public class MainActivity extends AppCompatActivity implements View.OnClickListener{ private TextView myTextView;
private Button myButton;
private MyAsyncTask myTask;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
myTextView = (TextView)this.findViewById(R.id.text_view);
myButton = (Button)this.findViewById(R.id.post);
myButton.setOnClickListener(this);
//主线程初始化异步任务
myTask = new MyAsyncTask();
//主线程启动异步任务,
myTask.execute(10);
} @Override
public void onClick(View v) {
//主线程取消异步任务
myTask.cancel(true);
} /**
* AsyncTask<T, Q, K> 是异步任务基类 包含三个泛型参数。
* T 类型参数为执行异步任务时的参数类型doInBackground(T)
* Q 类型参数为执行过程中的参数类型onProgressUpdate(Q)
* K 类型参数为执行结束onPostExecute(K)或中取消执行时的类型参数onCancelled(K)
*/
class MyAsyncTask extends AsyncTask<Integer, Integer, Long>{ @Override
//执行异步任务核心方法,主语T参数类型
protected Long doInBackground(Integer... params) {
int size = params[0];
long totalSize = 0l;
for(int i = 0; i < size; i++){
totalSize += 10000;
publishProgress((int) ((i / (float) size) * 100));
if(isCancelled()){
break;
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return totalSize;
} @Override
//开始执行异步任务前,更新UI线程。
protected void onPreExecute() {
myTextView.setText("downLoad start !!");
} @Override
//执行异步任务中,更新UI线程
protected void onProgressUpdate(Integer... values) {
int progress = values[0];
myTextView.setText(progress + "%");
} @Override
//执行异步任务后,更新UI线程
protected void onPostExecute(Long aLong) {
myTextView.setText("Task finished");
} @Override
//执行异步任务被取消后,跟新UI线程
protected void onCancelled(Long aLong) {
myTextView.setText("Task camcelled");
}
}
}

通过实例可以看出,SyncTask不但可以给主线程提供启动和停止接口,还可以给主线程上报过程。当然了开销也是有的。

实际上这种方式也可以用 Handler 原理分析和使用(一)中的例子实现。

以上都是主线程启动一个子线程完成任务。但是如果要做多个异步任务,该如何实现?

首先,从多个异步任务来考虑,如果还是各自不同的话,先考虑到的是线程池。这个在后面的多线程部分在说明。

还有一种方式就是使用HandlerThread。这个就是通过主线程获取其他线程给HandlerThread发消息,使其完成相关的任务。在例举说明HandlerThread使用之前,先看看以下例子。也是主线程给子线程发消息,让子线程处理任务。

 import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue; public class MainActivity extends AppCompatActivity implements View.OnClickListener{ private TextView myTextView;
private Button myButton;
private MyThread myThread;
private Handler myThreadHandler;
private int count = 0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
myTextView = (TextView)this.findViewById(R.id.text_view);
myButton = (Button)this.findViewById(R.id.post);
myButton.setOnClickListener(this);
//定义子线程
myThread = new MyThread();
//获取子线程的Handler
myThreadHandler = myThread.getHandler();
//启动子线程
myThread.start(); } @Override
public void onClick(View v) {
count++;
//通过子线程的Handler,主线程给子线程发送消息(添加任务)
myThreadHandler.sendEmptyMessage(count);
} /**
* 子线程
*/
public class MyThread extends Thread{
public Handler mThreadHandler = null;
//任务队列
public BlockingQueue<Integer> queue = null;
public MyThread(){
super();
queue = new ArrayBlockingQueue<Integer>(20);
//获取子线程的Looper
Looper mThreadLopper = Looper.myLooper();
//初始化子线程的Handler
mThreadHandler = new Handler(mThreadLopper, new Handler.Callback() {
@Override
//接收到主线程发的任务
public boolean handleMessage(Message msg) {
//任务添加到队列
queue.add(msg.what);
return false;
}
});
}
public Handler getHandler(){
return mThreadHandler;
}
public void run(){
while(true){
try{
//任务的处理
int what = queue.take();
Log.e("Test", "Click Button = " + what);
}catch(InterruptedException e){ } }
} }
}

上面的例子说明了两件事情。第一,非主线程有自己的Looper(很多文章说没有),第二Handler可以处理非主线程的任务。实际上上面的例子,使用了sendMessage()方法,其实际上用处并不是很广泛,甚至有些憋屈,本身已经有了一个MessageQueue,为什么还要使用一个ArrayBlockingQueue?

实际上上述的例子,完全可以通过HandlerThread来替代。例子如下

import android.os.Handler;
import android.os.HandlerThread;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView; public class MainActivity extends AppCompatActivity implements View.OnClickListener{ public TextView myTextView;
private Button myButton;
private HandlerThread myThread;
private Handler myThreadHandler;
private int count = 0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
myTextView = (TextView)this.findViewById(R.id.text_view);
myButton = (Button)this.findViewById(R.id.post);
myButton.setOnClickListener(this);
//初始化HandlerThread
myThread = new HandlerThread("handlerThread_test");
//启动HandlerThread
myThread.start();
//初始化HandlerThrand的Handler对象
myThreadHandler = new Handler(myThread.getLooper(), new Handler.Callback() {
@Override
//实现消息处理。
public boolean handleMessage(Message msg) {
int what =msg.what;
Log.e("Test", "Click Button = " + what);
return false;
}
});
} @Override
public void onClick(View v) {
count++;
//通过Handler给HandlerThread线程发送消息
myThreadHandler.sendEmptyMessage(count);
//通过Handler给HandlerThreand发送要执行的任务。
myThreadHandler.post(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Log.e("Test", "Hello world1");
}
});
myThreadHandler.post(new Runnable() {
@Override
public void run() {
Log.e("Test", "Hello world2");
}
});
}
}

从这个例子不难看出HandlerThread实际上是一个Thread,而这个Thread是负责处理Handler派发的消息和任务。此外值得注意有三点:

第一,只有一个线程来处理各种任务。

第一,执行的任务时有序的。也就是说顺序可以被控制。

第二,可以执行各种自定义的任务。

最后关于HandlerThread的退出:myThread.quit();

HandlerThread与SyncTask相比较,缺少执行过程的反馈。但是执行任务的多样性超过SyncTask。当然了都只启动了一个线程。

HandlerThread与Handler-Thread模式比较,也是缺少执行反馈。但是执行多任务时,HandlerThread却只需要一个线程。

所有的Handler就到这里了。也不经意间把SyncTask拿出来溜了一下。其他两篇

Handler 原理分析和使用(一)

Handler 原理分析和使用(二)

Handler完了。

上一篇:Android发展史


下一篇:iOS编码规范参考