首先是AsyncTask
这是一个用于异步处理数据的线程操作类。由于Android中存在UI线程的概念,只有在UI线程中才能对View(肉眼可见的地方)进行修改和调整。UI线程中是不能做一些耗时地操作的,比如说访问网络(http请求)、从SD卡读写数据(I/O操作)亦或者是比较复杂的数据运算,这些都是不能放在UI线程中进行的(会导致ANR异常)。
为了解决这个问题,Android系统提供了这个异步操作类。(以下是部分代码)
public abstract class AsyncTask<Params, Progress, Result> {
/**
* Override this method to perform a computation on a background thread. The
* specified parameters are the parameters passed to {@link #execute}
* by the caller of this task.
*
* This method can call {@link #publishProgress} to publish updates
* on the UI thread.
*
* @param params The parameters of the task.
*
* @return A result, defined by the subclass of this task.
*
* @see #onPreExecute()
* @see #onPostExecute
* @see #publishProgress
*/
@WorkerThread
protected abstract Result doInBackground(Params... params);
/**
* <p>Runs on the UI thread after {@link #doInBackground}. The
* specified result is the value returned by {@link #doInBackground}.</p>
*
* <p>This method won't be invoked if the task was cancelled.</p>
*
* @param result The result of the operation computed by {@link #doInBackground}.
*
* @see #onPreExecute
* @see #doInBackground
* @see #onCancelled(Object)
*/
@SuppressWarnings({"UnusedDeclaration"})
@MainThread
protected void onPostExecute(Result result) {
}
}
这里注意到doInBackground方法上的注解@WorkerThread和onPostExecute方法上的@MainThread,这两个注解就提示了我们,这两个方法是运行不同的线程上的。
通常我们会把耗时操作放在doInBackground方法中,然后将执行结果Result返回。从上面的注释中我们可以看到onPostExecute会跟在doInBackground之后执行,不同的是onPostExecute方法是在UI线程中执行的,在这里我们对View(肉眼可见的界面)进行操作了。还有onPostExecute方法中有一个Result参数,这个参数就是doInBackground方法中返回的Result,我们可以根据这个Result做相关的UI操作。
例子:
public class DecodeBitmapTask extends AsyncTask<String, Integer, Bitmap> {
private ImageView imageView;
public VideoShotTask(ImageView imageView) {
this.imageView = imageView;
}
@Override
protected Bitmap doInBackground(String... params) {
String sourcePath = params[0];
Bitmap bitmap = BitmapFactory.decodeFile(sourcePath);
return bitmap;
}
@Override
protected void onPostExecute(Bitmap result) {
if (imageView != null && result != null) {
imageView.setImageBitmap(result);
}
this.cancel(true);//执行完成之后可以取消任务
}
}
这就是一个从sd卡中加载图片,并绘制到ImageView上的过程。
使用上面这个类的方法也很简单
DecodeBitmapTask dbt = new DecodeBitmap(传入一个ImageView);
dbt.execute("传入一个图片资源路径");
这样就可以实现工作线程(子线程)与UI线程(主线程)之间的配合啦。
ps:当然AsyncTask的功能不止于此,我这里只是做个简单的例子。
HandlerThread
就像它的名字一样,它是由Handler和Thread有机结合起来的一个类。它区别于我们直接通过new Thread的方式创建线程,HandlerThread创建的线程是可以反复重用的,也就减少了因为new新的实例而导致的内存开销。而且它Handler中功能,使得我们对线程的使用更加的灵活。
//首先创建一个HandlerThread对象
HandlerThread mHT = new HandlerThread("传入线程的名字");
//随后启动线程
mHT.start();
//根据HandlerThread的Looper来创建一个Handler对象
Handler workHandler = new Handler( mHT.getLooper() ) {
@Override
public void handleMessage(Message msg) {
//这里是运行在工作线程中,而不是UI线程
switch(msg.what){
case 2:
//do something。。。
break;
}
}
});
//这里通过传统的Handler发送消息的方式,来触发线程
Message msg = Message.obtain();
msg.what = 2; //消息的标识
msg.obj = "B"; // 消息的存放
workHandler.sendMessage(msg);
// 最后不需要用的时候,结束线程,即停止线程的消息循环
mHT.quit();
如此一来,我们就可以通过Handler来操作、执行工作线程。这样做的好处就是减少了我们new Thread的操作,这样可以大大的减少内存泄漏的风险和过多的内存开销。
IntentService
这是一个Service与HandlerThread的结合体。首先我们知道Service是android的四大组件之一,长期在后台处理数据。但是它并不是一个线程,如果在Service中执行耗时操作就会产生ANR异常,那么当一个Service需要处理比较多的耗时任务时,就需要单独开启一个工作线程来完成。IntentService就是基于这种应用场景而诞生的。
IntentService继承自Service
//IntentService源码节选
@Override
public void onCreate() {
// TODO: It would be nice to have an option to hold a partial wakelock
// during processing, and to have a static startService(Context, Intent)
// method that would launch the service & hand off a wakelock.
super.onCreate();
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
/**
* This method is invoked on the worker thread with a request to process.
* Only one Intent is processed at a time, but the processing happens on a
* worker thread that runs independently from other application logic.
* So, if this code takes a long time, it will hold up other requests to
* the same IntentService, but it will not hold up anything else.
* When all requests have been handled, the IntentService stops itself,
* so you should not call {@link #stopSelf}.
*
* @param intent The value passed to {@link
* android.content.Context#startService(Intent)}.
* This may be null if the service is being restarted after
* its process has gone away; see
* {@link android.app.Service#onStartCommand}
* for details.
*/
@WorkerThread
protected abstract void onHandleIntent(@Nullable Intent intent);
在它的onCreate方法中可以看到,它的内部其实就是通过封装HandlerThread来实现工作线程的。当我们要使用它时,需要先继承IntentService,然后实现它的抽象方法onHandleIntent方法。(由于它也是一个Service,别忘了在AndroidManifest中配置它)
public class TestIntentService extends IntentService {
/**
* Creates an IntentService. Invoked by your subclass's constructor.
*
* @param name Used to name the worker thread, important only for debugging.
*/
public TestIntentService(String name) {
super(name);
}
@Override
protected void onHandleIntent(@Nullable Intent intent) {
//do something。。。
//此时也是运行在工作线程(子线程)中哦
//Intent用于传递我们需要的数据,每一次通过startService方法触发,都会按顺序执行,不会无序执行
}
}
在我们使用这个IntentService的时候,就是这样:
Intent intent = new Intent(MainActivity.this, TestIntentService.class);
startService(intent);//intent当中记得要存放你需要传递的参数哦
就像我上面的注释中说的那样,每次startService,都会按照顺序去执行,并不会像我们new Thread那样,顺序完全随机。并且它与Service不同的地方在于,它不需要手动执行stopService方法来终止服务。因为在它的源码中:
//在IntentService的内部类中可以看出来
//每一次执行完任务,都会自己调用stopSelf方法
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
onHandleIntent((Intent)msg.obj);
stopSelf(msg.arg1);
}
}