提到了兩個原因:
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();
}
}
}