Android中AsyncTask(異步任務,實際就和handler的作用差不多)

Android API中有提到,AsyncTask非常適合短時間異步操作。如果要執行長時間操作,最好使用線程池Executor:
提到了兩個原因:
AsyncTask的生命週期沒有跟Activity的生命週期同步
容易內存泄露

AsyncTask和Activity的生命週期
      如果你在一個Activity中創建了一個AsyncTask,你旋轉了屏幕,這個Activity將會被銷燬並且會重新創建一個新的實例。但是AsyncTask沒有銷燬,它將會繼續執行直到完成。當它執行完成後,它實際上是更新了上一個已經不存在的Activity,如果你原本想在onPostExecute()中更新UI的話,這時的AsyncTask將不會更新新的Activity,並且這個操作會引發一個異常:java.lang.IllegalArgumentException。
      如果你是想要在onPostExecute()中關閉一個dialog,則會發生:java.lang.IllegalArgumentException: View not attached to window manager(前提是你忘記在Activity的onStop()中忘記dismiss)。不僅如此,還會在show()的調用出拋出一個lead window的異常

內存泄露問題
      在Activity中作爲內部類創建AsyncTask很方便。因爲AsyncTask在執行完成或者執行中需要使用Activity中的view,因爲內部類可以直接訪問外部類的域(也就是變量)。然而這意味着內部類會持有外部類的一個引用。
      當長時間運行時,因爲AsyncTask持有Activity的引用,所以即使當該Activity不再顯示時Android也無法釋放其佔用的資源。


AsyncTask:(實際就和handler的作用差不多)
使用AsyncTask的具體步驟:注意3個泛型必須基本數據類型對象,也就是(Integer,String之類)
1.新建一個類,extends AsyncTask類<Params, Progress, Result>{}//三個泛型可用大寫的Void替代(Void是小寫void的對象類型)
2.複寫其抽象方法,在異步任務(也就是doInBackground方法)執行之前,執行該方法,在主線程執行
protected void onPreExecute() {super.onPreExecute();}
3.複寫抽象方法,該方法在後臺執行(可以理解爲子線程),可以做耗時的工作
protected Result doInBackground(Params... params){return null;}可以接收到doInBackground返回數據
4.複寫其方法抽象方法,在異步任務(也就是doInBackground方法)執行之後,執行該方法,在主線程執行
protected void onPostExecute(Void result) {super.onPostExecute(result);}
5.開啓一個異步任務,在主線程裏新建繼承了AsyncTask自定義的類,調用execute()方法.
        new myAsyncTasK().execute();//execute()方法一定要用,相當於開啓線程的start,調了1個小時的bug.
 
關於AsyncTask參數的說明
1.類中的三個泛型:
    params:第一個泛型,就是5.execute方法的參數類型(其實就是他傳的實際參數),也是3.doInBackground方法的參數類型
    提示:3.doInBackground(Params... params){內部使用時,params就是對應類型的數組,Prarms[0]就是第一個Params}
 
    Progress:第二個泛型,就是publishProgress(必須在3.doInBackground方法裏調用)方法的參數類型,他負責發佈進度,類似進度條,
    也是onProgressUpdate方法的參數類型,他得到的是來自publishProgress的實際參數,進度更新時調用,在主線程中執行,可更新UI
    提示:使用到第二個泛型,就要使用到publishProgress,並繼續使用到onProgressUpdate(此方法要複寫,具體格式如下:)
    protected void onProgressUpdate(Progress... values){super.onProgressUpdate(values);}//alues就是對應類型的數組
 
    Result:第三個泛型,既是3.doInBackground的返回值類型,並且它還是OnPostExecute的參數類型;
    應用場景:在子線程(doInBackground)獲取信息,在OnpostExcute裏去顯示;
 

示例代碼:

Android API中有提到,AsyncTask非常適合短時間異步操作。如果要執行長時間操作,最好使用線程池Executor:
提到了兩個原因:
AsyncTask的生命週期沒有跟Activity的生命週期同步
容易內存泄露

AsyncTask和Activity的生命週期
      如果你在一個Activity中創建了一個AsyncTask,你旋轉了屏幕,這個Activity將會被銷燬並且會重新創建一個新的實例。但是AsyncTask沒有銷燬,它將會繼續執行直到完成。當它執行完成後,它實際上是更新了上一個已經不存在的Activity,如果你原本想在onPostExecute()中更新UI的話,這時的AsyncTask將不會更新新的Activity,並且這個操作會引發一個異常:java.lang.IllegalArgumentException。
      如果你是想要在onPostExecute()中關閉一個dialog,則會發生:java.lang.IllegalArgumentException: View not attached to window manager(前提是你忘記在Activity的onStop()中忘記dismiss)。不僅如此,還會在show()的調用出拋出一個lead window的異常

內存泄露問題
      在Activity中作爲內部類創建AsyncTask很方便。因爲AsyncTask在執行完成或者執行中需要使用Activity中的view,因爲內部類可以直接訪問外部類的域(也就是變量)。然而這意味着內部類會持有外部類的一個引用。
      當長時間運行時,因爲AsyncTask持有Activity的引用,所以即使當該Activity不再顯示時Android也無法釋放其佔用的資源。


AsyncTask:(實際就和handler的作用差不多)
使用AsyncTask的具體步驟:注意3個泛型必須基本數據類型對象,也就是(Integer,String之類)
1.新建一個類,extends AsyncTask類<Params, Progress, Result>{}//三個泛型可用大寫的Void替代(Void是小寫void的對象類型)
2.複寫其抽象方法,在異步任務(也就是doInBackground方法)執行之前,執行該方法,在主線程執行
protected void onPreExecute() {super.onPreExecute();}
3.複寫抽象方法,該方法在後臺執行(可以理解爲子線程),可以做耗時的工作
protected Result doInBackground(Params... params){return null;}可以接收到doInBackground返回數據
4.複寫其方法抽象方法,在異步任務(也就是doInBackground方法)執行之後,執行該方法,在主線程執行
protected void onPostExecute(Void result) {super.onPostExecute(result);}
5.開啓一個異步任務,在主線程裏新建繼承了AsyncTask自定義的類,調用execute()方法.
        new myAsyncTasK().execute();//execute()方法一定要用,相當於開啓線程的start,調了1個小時的bug.
 
關於AsyncTask參數的說明
1.類中的三個泛型:
    params:第一個泛型,就是5.execute方法的參數類型(其實就是他傳的實際參數),也是3.doInBackground方法的參數類型
    提示:3.doInBackground(Params... params){內部使用時,params就是對應類型的數組,Prarms[0]就是第一個Params}
 
    Progress:第二個泛型,就是publishProgress(必須在3.doInBackground方法裏調用)方法的參數類型,他負責發佈進度,類似進度條,
    也是onProgressUpdate方法的參數類型,他得到的是來自publishProgress的實際參數,進度更新時調用,在主線程中執行,可更新UI
    提示:使用到第二個泛型,就要使用到publishProgress,並繼續使用到onProgressUpdate(此方法要複寫,具體格式如下:)
    protected void onProgressUpdate(Progress... values){super.onProgressUpdate(values);}//alues就是對應類型的數組
 
    Result:第三個泛型,既是3.doInBackground的返回值類型,並且它還是OnPostExecute的參數類型;
    應用場景:在子線程(doInBackground)獲取信息,在OnpostExcute裏去顯示;
 
示例代碼:

public class MainActivity extends Activity {
    private ProgressDialog pd;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
//        開啓一個異步任務,在主線程裏新建繼承了AsyncTask自定義的類,調用execute()方法.
        new myAsyncTasK().execute("www.dslkfja.com");
    }
 
    public class myAsyncTasK extends AsyncTask<String,Integer,ArrayList<String>>{
//        在異步任務執行之前,執行該方法,在主線程執行
        protected void onPreExecute() {
            System.out.println(Thread.currentThread().getName()+"    "+"onPreExecute在工作");
            super.onPreExecute();
            pd = new ProgressDialog(MainActivity.this);
            pd.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
            pd.setMax(10);
            pd.show();
        }
//        該方法在後臺執行(可以理解爲子線程),可以做耗時的工作
        protected ArrayList<String> doInBackground(String... params) {
            System.out.println("網站是"+params[0]);
            SystemClock.sleep(1000);
            System.out.println(Thread.currentThread().getName()+"    "+"doInBackground在後臺忙碌");
            for (int i = 0; i <10; i++) {
//                發佈進度
                publishProgress(i);
            }
            ArrayList<String> al=new ArrayList<String>();
            al.add("aaa");
            al.add("vvv");
            al.add("ccc");
            return al;
        }   
//        進度更新時調用,在主線程中執行,所以可以更新UI
        protected void onProgressUpdate(Integer... values) {
            super.onProgressUpdate(values);
            pd.setProgress(values[0]);
            System.out.println(Thread.currentThread().getName()+"我是onProgressUpdate"+values[0]);
        }
//        在異步任務執行之後,執行該方法,在主線程執行
        protected void onPostExecute(ArrayList<String> result) {
            pd.dismiss();
            super.onPostExecute(result);
            System.out.println(result);
            System.out.println(Thread.currentThread().getName()+"    "+"onPostExecute在清理着垃圾");
            Toast.makeText(getApplicationContext(), "進度條完成",0).show();
        }
    }
}





發佈了94 篇原創文章 · 獲贊 37 · 訪問量 25萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章