1. 程式人生 > >Android AsyncTask 取消全部任務 , 解決記憶體洩漏問題

Android AsyncTask 取消全部任務 , 解決記憶體洩漏問題

以下程式碼具備的功能: 

1. 取消當前新增的所有 AsyncTask , 儘量減少重複的網路請求任務

(場景: 我們需要在一個介面中定時每 10s 請求一次網路獲取一次資料 ,我們知道網路請求時間是不固定的 ,可能很快的請求完成,也可能很慢,因此,我為了儘量節省開銷,希望每次都能在指定的時間執行一次網路請求就好了)

2. 嘗試解決記憶體洩漏問題

(記憶體洩漏,多是由於有些介面或物件銷燬或生命週期結束後,仍然有一些引用持有該介面或物件 ,如: 想在一個已經銷燬的介面中進行更新UI操作,

記憶體洩漏帶來的影響: 隨著洩漏的累積,app將消耗完記憶體)

3. 迴圈請求網路

實現定時請求網路的功能

程式碼開始 ---->>>

Activity 部分: 

public class MainActivity extends AppCompatActivity{

    private static final String TAG = "MainActivity";

    private List<String> showData = new ArrayList<>();

    private ImRunnable mImRunnable;

    Handler mHandler = new Handler();
    private MainAdapter mAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        initView();

        mImRunnable = new ImRunnable();
        mHandler.removeCallbacks(mImRunnable);//清除上一次任務的影響

        mHandler.postDelayed(mImRunnable, 300);//延時請求網路

    }

    private void initView() {

        RecyclerView rcv = (RecyclerView) findViewById(R.id.rcv);
        rcv.setLayoutManager(new GridLayoutManager(this, 4));
        mAdapter = new MainAdapter(showData);
        rcv.setAdapter(mAdapter);

    }

    //執行延時任務
    private class ImRunnable implements Runnable, OnResponseCallback {
        @Override
        public void run() {

            Log.i("NotifyService", "run: " + Thread.currentThread());

            HashMap<String, String> parameters = new HashMap<>();
            parameters.put("key", "value");
            NetUtils netUtils = new NetUtils(MainActivity.this,this);
            NetUtils.putTaskFloor(netUtils);//todo 儲存每次建立的 AsyncTask 物件(弱引用),在取消全部的時候會用到
            netUtils.execute(new TestWeb(parameters));

            //重複執行本身
            mHandler.postDelayed(this, 300);

        }

        @Override
        public void onSuccess(List<String> stringList) {

            Log.i(TAG, "onSuccess: ");

            if (stringList.get(0).equals("pass")) {

                stringList.remove(0);
                showData.clear();
                showData.addAll(stringList);
                mAdapter.setData(showData);
                mAdapter.notifyDataSetChanged();

                Toast.makeText(MainActivity.this, "更新了資料!", Toast.LENGTH_SHORT).show();

            } else {

                Toast.makeText(MainActivity.this, "資料讀取失敗", Toast.LENGTH_SHORT).show();
            }

        }

        @Override
        public void onFail() {

            Log.i(TAG, "onFail: ");
        }
    }


    @Override
    protected void onDestroy() {
        super.onDestroy();
        showData.clear();
        showData = null;
        mHandler.removeCallbacks(mImRunnable);
        NetUtils.isNeedLoading = false;
        NetUtils.cancelAllRunningTask();
        int size = NetUtils.allTask.size();
        Log.i(TAG, "onDestroy: 退出後還有多少: "+size);

        System.gc();
    }



}

AsyncTask 部分:

public class NetUtils extends AsyncTask<BaseRequest, Void, List<String>> {

    public static List<WeakReference<NetUtils>> allTask = new ArrayList<>();
    private WeakReference<Activity> weakAty;

    private final OnResponseCallback mOnResponseCallback;
    public static boolean isNeedLoading = true;
    public static boolean isNeedSingleTask = true;//是否需要每次只允許一個任務執行

    public NetUtils(Activity activity, OnResponseCallback onResponseCallback) {

        this.mOnResponseCallback = onResponseCallback;
        weakAty = new WeakReference<Activity>(activity);

    }

    public static void putTaskFloor(NetUtils netUtils) {

        allTask.add(new WeakReference<NetUtils>(netUtils));

    }

    @Override
    protected void onPreExecute() {
        super.onPreExecute();

    }

    @Override
    protected List<String> doInBackground(BaseRequest... voids) {

        if (!isNeedLoading) {
            return null;
        }

        if (isCancelled()) {
            return null;
        }

        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        Log.e("NetUtils", "doInBackground:");


        return null;

    }

    @Override
    protected void onPostExecute(List<String> stringList) {
        super.onPostExecute(stringList);

        isNeedLoading = true;

        if (isNeedSingleTask) {

            cancelAllRunningTask();//todo 拿到結果後,將再等待中的任務全部取消

        }

        Activity mActivity;

        Activity activity = mActivity = (Activity) weakAty.get();

        if (activity != null && !activity.isFinishing()) {
       
       //activity != null && !activity.isFinishing() 決定了是否繼續讓持有的 activity 做事
       //即只有噹噹前的 activity 沒有 finish 的時候我們才有必要去更新UI

            if (stringList != null) {

                if (stringList.get(0).equals("pass")) {

                    if (mOnResponseCallback != null) {

                        mOnResponseCallback.onSuccess(stringList);

                    }

                } else {

                    if (mOnResponseCallback != null) {

                        mOnResponseCallback.onFail();

                    }

                }

            } else {
                if (mOnResponseCallback != null) {
                    mOnResponseCallback.onFail();
                }
            }

        }

        Log.e("NetUtils", "onPostExecute: 正在執行 AsyncTask from NetUtils");


    }

  
    public static void cancelAllRunningTask() {

        if (allTask != null && allTask.size() > 0) {

            for (int i = 0; i < allTask.size(); i++) {

                NetUtils netUtils = allTask.get(i).get();

                if (!netUtils.isCancelled()) {
                    netUtils.cancel(true);//沒有取消就取消
                    Log.w("NetUtils", "cancelAll: 正在執行 AsyncTask from NetUtils");
                    allTask.remove(i);
                } else {
                    allTask.remove(i);
                }

                int size = NetUtils.allTask.size();
                Log.i("NetUtils", "cancelAllRunningTask: 取消一個任務後還有多少: "+size);

            }

        }

    }

}
public interface OnResponseCallback {
    void onSuccess(List<String> stringList);
    void onFail();

}

結束: 如果有更好的寫法,請不吝賜教 [握手]