安卓中实现异步任务的方式莫过于以下三种方式:.
其一 Thread
其二 AsyncTask
其三 ExcutorService及其实现类——ThreadPoolExecutor
其四 较不常用的IntentService
Thread是安卓异步线程的基础,这里简单介绍一下他的两种实现方式及其更新UI的方式
1,继承Thread
private class MyThread extends Thread {
@Override
public void run() {
super.run();
//run something time-consuming
}
}
调用:new MyThread().start();
2,实现Runnable接口
new Thread(new Runnable() {
@Override
public void run() {
//run something time-consuming
}
}).start();
更新UI的方式:
1,Handler - Message
Message msg = new Message();
msg.what = 0;
myHandler.sendMessage(msg);
//以上Message步骤一般写于异步的run()方法中
Handler myHandler = new Handler() {
public void handleMessage(Message msg) {
switch (msg.what) {
case 0:
//update UI
break;
default:
break;
}
};
};
2, runOnUiThread(写于异步的run()方法中)
runOnUiThread(new Runnable() {
public void run() {
//update UI
}
});
接下来介绍AsyncTask(异步任务),我们从最权威的google官方文档来了解它,文档中对它的描述大致如下:
AsyncTask继承于Object类,位置在android.os.AsyncTask。AsyncTask易用于UI线程。这个类可以执行后台操作,并可直接更新UI,而不用其他更新UI方式(即上面写的两种方式)asynctasks应该用于短时间的异步任务(最多几秒钟)如果你需要保持线程运行很长一段时间,我们强烈建议您使用java.util.concurrent包(即是待会要介绍的Executors、ExecutorService所在的包),如执行API提供的线程池和futuretask。
一个异步任务是由3个泛型参数和4个步骤onpreexecute(),doInBackground(),onProgressUpdate()和onpostexecute()组成。
其中doInBackground()方法在AsyncTask源码里是唯一定义为抽象的方法:
@WorkerThread
protectedabstract Result doInBackground(Params... params);
所以这个方法是必须重载的,而其他方法是非必须的。
3个参数类型如下:
Params: 执行后台任务时传递的参数类型
Progress: 执行后台任务时更新进度的进度值类型
Result: 后台执行任务后完成的返回值类型
这三个类型可以为空: private class MyTask extends AsyncTask<Void, Void, Void> { ...}
关于4个步骤的解释看下面代码:
public class MyTask extends AsyncTask<String, Integer, Long> {
@Override
protected Long doInBackground(String... params) {
// 执行耗时的操作
return Long;
}
@Override
protected void onPreExecute() {
//启动task前的预备工作
super.onPreExecute();
}
@Override
protected void onPostExecute(Long result) {
// 返回结果 ,此处更新UI
super.onPostExecute(result);
}
@Override
protected void onProgressUpdate(Integer... values){
//更新操作的进度
super.onProgressUpdate(values);
}
@Override
protected void onCancelled(Long result) {
// 取消Task任务
super.onCancelled(result);
}
@Override
protected void onCancelled() {
// 取消Task任务
super.onCancelled();
}
}
调用:new MyTask ().execute(s,i,l);
其中调用 cancel(boolean mayInterruptIfRunning) 方法可以随时取消任务。
注意事项:
AsyncTask必须在UI线程中实例化后执行,否则会出现不执行onPostExecute()方法的情况;不能人为调用onpreexecute() onpostexecute doInBackground onProgressUpdate,一个AsyncTask任务只能执行一次,多次调用将会抛出异常。Android3.0以前,AsyncTask的全局线程池只有5个工作线程,线程池总大小为128,也就是说,一个APP如果运用AsyncTask技术来添加128个线程,那么同一时间最多只能有5个线程同时运行,剩下123个线程将被阻塞。
而3.0之后的AsyncTask同时线程最大运行数将由系统核数决定了
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
private static final int CORE_POOL_SIZE = CPU_COUNT + 1;
private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
private static final int KEEP_ALIVE = 1;
并且默认同时只能有1个任务在执行。
AsyncTask相关介绍就到这里止,然后就是ExcutorService了,介绍ExcutorService之前我们先认识Executors,Executors是Java5以后新增的关于启动、调度、管理线程的API,官方简要的介绍是:
Factory andutility methods for Executor, ExecutorService, ScheduledExecutorService,ThreadFactory, and Callable classes defined in this package.
大意就是说:Executors中定义了 Executor、ExecutorService、ScheduledExecutorService、ThreadFactory 和 Callable 类的工厂和创建方法。要想得到这些对象的实例,只有靠我的方法才行,大体就是这个意思。
ExecutorService提供了管理和终止的方法,相当于一个线程池的管理工具,通过它可实现线程复用,线程队列,定时执行、单线程、并发数控制,那么使用它有什么好处呢?显然它可以重用存在的线程,减少对象创建、消亡的开销,有效控制最大并发线程数,提高系统资源的使用率,降低了GC的压力,提升了性能。
废话不多说,直接看代码及介绍:
//可缓存线程池,如果线程池长度超过处理需求,可灵活回收空闲线程,若无可回收,则新建线程
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
cachedThreadPool.execute(new Runnable() {
@Override
public void run() {
//run something time-consuming
}
});
// ExecutorService 的submit方法介绍:执行execute方法无返回值,执行submit方法返回一个Future对象,
//可通过此对象获取到执行结果的返回值和捕捉到对应的异常;submit方法可传入Callable对象和Runnable对象,
//当传入Runnable对象返回的Future对象执行其get()方法将返回null。
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
Future<String> future = cachedThreadPool.submit(new Callable<String>() {
@Override
public String call() throws Exception {
return "result";
}
});
try {
future.get();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
finally {
executorService.shutdown();
}
//定长为3的线程池,可控制线程最大并发数,超出的线程会在队列中等待和复用执行完成的线程
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
fixedThreadPool.execute(new Runnable() {
@Override
public void run() {
//run something time-consuming
}
});
//定长为5线程池,延迟3秒后执行。
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
scheduledThreadPool.schedule(new Runnable() {
@Override
public void run() {
//run something time-consuming
}
} ,3, TimeUnit.SECONDS);
//定期执行,延迟1秒后每3秒执行一次
scheduledThreadPool. scheduleAtFixedRate (new Runnable() {
@Override
public void run() {
//run something time-consuming
}
},1, 3, TimeUnit.SECONDS);
以上便是线程池大概内容,最后再来介绍一下IntentService,这是一个抽象类,所以必须继承它才能使用。IntentService说白了就是HandlerThread、Handler和Service的集合体,一般用于长时间的后台执行或监听,在Activity退出后依然在后台执行等功能,如监听IO口的高低电平变化,那为什么会说它用的少呢,因为我们一般会自己定义线程,Handler于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);
}
可以看到的是在IntentService的onCreate中开启了一个HandlerThread线程,并且获取其Looper,构建了一个ServiceHandler,然后我们来看看ServiceHandler
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);
}
}
可以看到的是,ServiceHandler中只有一个方法handlerMessage,里面是一个抽象方法onHandlerIntent和stopSelf,这里说一下这两个方法,其中onHandlerIntent在子类实现,而从上面代码可以看到它是在ServiceHandler的handlerMessage方法里面被调用,而ServiceHandler是由子线程的looper构造而成,所以onHandlerIntent很明显就是执行耗时操作的方法,而stopSelf是停止服务方法,要说明的是这个方法执行后不会立即停止,而是会等待最后一个任务执行完成才会停止。
抽象方法onHandlerIntent:
@WorkerThread
protected abstract void onHandleIntent(Intent intent);
接下来我们说说怎么执行,再看源码:
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
onStart(intent, startId);
return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
}
@Override
public void onStart(Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
可以看到在onStartCommand中调用了onStart,onStart就是把传进来的intent和startid以msg形式通过mSerivice的sendMessage把消息发送至消息队列,,Looper再把消息取出交由ServiceHandler的handleMessage进行处理,最终回调子类的onHandleIntent。
所以IntentService的使用方法:
1,写一个子类继承IntentService
2,复写抽象方法,其中onHandleIntent编写处理逻辑
3,携带intent,启动一个Service即可
Intent service = new Intent(this, MyIntentService.class);
service.putExtra("yph_key", "yph_value");
startService(service);
OK,这篇安卓异步完全解析就写到这里,有兴趣深究的同学建议可以带着问题的某个点去源码中理解其具体执行方式与步骤,不仅可以加深我们的理解,而且阅读源码可以很大程度能增强我们对java设计模式的理解。
最后给大家提个醒:在activity or service关闭时要终止异步的任务,否则因为任务还在执行可能对某些对象还存在引用,那么就会造成内存泄漏等异常情况的发生。