Android的异步任务有很多实现方法,最常见的如Handler、Thread、AsyncTask;还有一些开源项目也可以做到异步任务和线程间通信等功能,例如:EventBus、RxAndroid等,我们这里就不讨论用哪种实现方式更好,只是根据实际需求进行合适的筛选。
笔者公司的项目算是大型的互联网金融类的App,由于历史架构原因未用到一些新的开源项目,也不能盲目引入这些开源的项目,所以只能在Handler、Thread、AsyncTask中选择一个进行封装了。封装要求:调用便捷、灵活、可扩展,最重要是防止内存泄露,最好能在调用者销毁时自动中断并释放所有异步任务资源。
Handler已经不能再熟悉了,封装起来虽然更能得心应手,但是考虑时间问题觉得AsyncTask更简单,因为google已经对异步任务进行了封装,所以才有了AsyncTask这个类。但要注意的是AsyncTask是顺序执行的,也就是并不适合并发需求,如有并发需求请跳过。
整个封装简单,直接上工具类代码:
package asyncTask;
import android.util.Log;
import java.lang.ref.WeakReference;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* 异步任务工具类
* 支持任务的执行与Activity生命周期进行绑定
*/
public class AsyncTaskUtil {
private static Map<String,HashMap<Integer,WeakReference<MyAsyncTask>>> taskMap = new ConcurrentHashMap<>();
/**
* 异步任务
* @param obj 请求标识
* @param call 回调
* @param params 入参
*/
public static <T> void doAsync(Object obj, AsyncCall<Object,Integer,T> call, Object... params){
MyAsyncTask task = new MyAsyncTask<Object, Integer, T>() {
@Override
protected T doInBackground(Object... params) {
try {
return call.onCall(params);
} catch (Exception e){
}
return null;
}
@Override
protected void onProgressUpdate(Integer... values) {
call.onProgressUpdate(values);
}
@Override
protected void onPreExecute() {
call.onPreCall();
}
@Override
protected void onPostExecute(T t) {
call.onCallFinished(t);
call.cancel(true);
destroyTask(obj, this);
}
};
call.bindTask(task);
addTask(obj, task);
task.execute(params);
}
/**
* 异步任务
* @param obj 请求标识
* @param call 回调
* @param params 入参
*/
public static void doAsync(Object obj, AsyncCallSimple call, Object... params){
MyAsyncTask task = new MyAsyncTask(){
@Override
protected Object doInBackground(Object[] params) {
try {
return call.onCall(params);
} catch (Exception e){
}
return null;
}
@Override
protected void onPostExecute(Object o) {
call.onCallFinished(o);
call.cancel(true);
destroyTask(obj, this);
}
@Override
protected void onPreExecute() {
call.onPreCall();
}
@Override
protected void onProgressUpdate(Object[] values) {
call.onProgressUpdate(values);
}
};
call.bindTask(task);
addTask(obj, task);
task.execute(params);
}
/**
* 销毁(释放资源并防止多线程在页面销毁时操作UI):请在Activity的onDestroy方法中调用
* @param obj 请求标识
*/
public static void destroy(Object obj){
final String tag = obj.getClass().getName();
HashMap<Integer,WeakReference<MyAsyncTask>> map = taskMap.get(tag);
if(null != map){
for(Map.Entry<Integer,WeakReference<MyAsyncTask>> entry : map.entrySet()){
if(null != entry.getValue().get()){
MyAsyncTask task = entry.getValue().get();
showLog("destroy["+tag+"] task="+ task.hashCode());
task.cancel(true);
}
}
taskMap.remove(tag);
}
}
private static void addTask(Object obj, MyAsyncTask task){
final String tag = obj.getClass().getName();
HashMap<Integer,WeakReference<MyAsyncTask>> map = taskMap.get(tag);
if(null == map){
map = new HashMap<Integer,WeakReference<MyAsyncTask>>();
map.put(task.hashCode(),new WeakReference<MyAsyncTask>(task));
taskMap.put(tag, map);
}else{
map.put(task.hashCode(),new WeakReference<MyAsyncTask>(task));
}
showLog("add["+tag+"] task="+ task.hashCode());
}
private static void destroyTask(Object obj, MyAsyncTask task){
final String tag = obj.getClass().getName();
HashMap<Integer,WeakReference<MyAsyncTask>> map = taskMap.get(tag);
if(null != map){
WeakReference<MyAsyncTask> wTask = map.get(task.hashCode());
if(null != wTask){
MyAsyncTask myTask = wTask.get();
showLog("destroy["+tag+"] task="+ myTask.hashCode());
map.remove(myTask);
taskMap.put(tag,map);
myTask.cancel(true);
}
if(map.size() == 0){
taskMap.remove(tag);
}
}
}
private static void showLog(String msg){
Log.d("AsyncTaskUtil",msg);
}
}
工具类中使用了两个抽象类:
异步任务回调抽象类
package asyncTask;
public abstract class AsyncCallAbs<Object,Integer,T> {
//UI线程执行:在onCall之前执行
abstract void onPreCall();
//非UI线程执行:执行耗时操作
abstract T onCall(Object[] objects) throws Exception;
//非UI线程执行:用于通知进度更新
abstract void publishProgress(Integer... values);
//UI线程执行:更新进度
abstract void onProgressUpdate(Integer[] values);
//UI线程执行:异步任务执行完毕
abstract void onCallFinished(T result);
abstract void cancel(boolean mayInterruptIfRunning);
}
package asyncTask;
//Object 启动任务执行的输入参数。
//Integer 后台任务执行的百分比。
//T 后台执行任务最终返回的结果,比如String。
public class AsyncCall<Object,Integer,T> extends AsyncCallAbs<Object,Integer,T> {
private MyAsyncTask task;
public void bindTask(MyAsyncTask task){
this.task = task;
}
@Override
public T onCall(Object[] objects) throws Exception {
return null;
}
@Override
public void onCallFinished(T result) {
}
@Override
public void onPreCall() {
}
@Override
public void onProgressUpdate(Integer[] values) {
}
@Override
public void publishProgress(Integer... values) {
if(null != task)
task.publishProgress(values);
}
@Override
public void cancel(boolean mayInterruptIfRunning) {
if(null != task){
task = null;
}
}
}
Activity中调用方法
AsyncTaskUtil.doAsync(this,new AsyncCall<Object, Integer, String>(){
@Override
public String onCall(Object[] obj) throws Exception {
for(int i=0;i<10;i++){
publishProgress(i);
Thread.sleep(200);
}
return obj[0].toString()+" "+obj[1].toString();
}
@Override
public void onCallFinished(String result) {
tv.setText(result);
}
@Override
public void onProgressUpdate(Integer[] values) {
tv.setText(values[0].toString());
}
},"hello","world");
该方法调用时会每0.2秒刷新一下TextView,请在Activity的onDestroy方法中增加销毁异步任务方法的调用(也可以自己监听Activity生命周期进行销毁操作):
@Override
protected void onDestroy() {
AsyncTaskUtil.destroy(this);
super.onDestroy();
}
下面提供了一个异步任务的简单回调类:
package asyncTask;
public class AsyncCallSimple extends AsyncCallAbs {
private MyAsyncTask task;
public void bindTask(MyAsyncTask task){
this.task = task;
}
@Override
public void onPreCall() {
}
@Override
public Object onCall(Object[] objects) throws Exception {
return null;
}
@Override
public void publishProgress(Object... values) {
if(null != task)
task.publishProgress(values);
}
@Override
public void onProgressUpdate(Object[] values) {
}
@Override
public void onCallFinished(Object result) {
}
@Override
public void cancel(boolean mayInterruptIfRunning) {
if(null != task){
task = null;
}
}
}
最后说一下MyAsyncTask类,该类只是对原生的AsyncTask类所以一点修改,将publishProgress方法的private改成public。
public final void publishProgress(Progress... values) {
if (!isCancelled()) {
getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
new AsyncTaskResult<Progress>(this, values)).sendToTarget();
}
}