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();
}
}