Android之AsyncTask異步任務——防止內存泄露

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




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章