在如何使用ProgressDialog當中, 我們假設一個程式在執行,
會跳出一個ProgressDialog來顯示程式正在執行,
讓使用者不會以為程式當機。
但是實際上, 我們並不知道程式何時才會執行完成,
假設我們在下載一個檔案, 結果網路斷掉, 那麼ProgressDialog還是一直顯示著,
使用者還是會不耐煩的,
因此, 我們需要一個方式, 來計算還剩下多少時間,
這時候, AsyncTask是一個很方便的工具,
他可以幫你去除一些煩人的執行緒問題。
在官方網站有給一個很詳細的範例, 並且使用真正的網路下載來判斷進度,
但是為了理解這個流程, 因此我用假的進度來模擬整個步驟。
首先建立一個專案, 剛開始只是一個很簡單的Activity,
接下來就是建立我們的AsyncTask,
從官網的範例可以知道,
http://developer.android.com/reference/android/os/AsyncTask.html
在這之前, 我們可以看到網站上說明,
必須先繼承AsyncTask,
然後我們必須實作四個方法, 分別是
而這四個方法傳入的參數, 必須和繼承AsyncTask後面的泛型型態是相同的,
先來解釋這四個方法的意義,
第一個方法onPreExecute()可以從名稱知道, 他是在進行一些初始化的工作。
第二個方法是doInBackground()會傳入一個參數, 這個參數的數量是不定的,
也就是說, 你可以傳入零到數個參數也不是問題, 從官網的例子來看,
當宣告這個類別的物件時候, 只要呼叫execute這個方法,
傳入你想下載的網址, 就可以開始使用它了。
第三個方法是onProgressUpdate(), 它一樣會傳入一些參數, 也是不定數量的,
而這個方法通常是在執行onInBackground的時候, 才會去呼叫它,
只要執行publishProgress()這個方法,
就會呼叫onProgressUpdate(), 利用這個方法, 就可以讓程式顯示目前進度為何。
最後一個方法是onPostExecute(), 這個用來接收結果,
通常你在onProgressUpdate()回傳的結果, 就會當參數傳到這個方法,
不過你要注意型態, 才不會沒有傳入。
現在來看一下範例怎麼寫的。
這樣就可以很清楚知道哪些參數是什麼功用,
雖然從型態就可以了解是如何對應的,
但是萬一我們的型態設定為相同的話, 有可能會造成錯亂,
所以還是了解一下位置比較妥當。
一開始先加入一個ProgressbarDialog用來計算我們的進度,
紅色那行一定要加入, 這樣才可以看到進度。
這樣才不會一下子就跑完了,
這邊可以參考官網真正的下載檔案, 然後設定progressbar的進度。
然後利用ProgressbarDialog的方法去設定進度。
這時候我們將dialog消滅, 就可以回到原本的畫面了。
程式碼
http://uploadingit.com/file/r6oanakevrc0onmm/ProgressBarDemo.zip
會跳出一個ProgressDialog來顯示程式正在執行,
讓使用者不會以為程式當機。
但是實際上, 我們並不知道程式何時才會執行完成,
假設我們在下載一個檔案, 結果網路斷掉, 那麼ProgressDialog還是一直顯示著,
使用者還是會不耐煩的,
因此, 我們需要一個方式, 來計算還剩下多少時間,
這時候, AsyncTask是一個很方便的工具,
他可以幫你去除一些煩人的執行緒問題。
在官方網站有給一個很詳細的範例, 並且使用真正的網路下載來判斷進度,
但是為了理解這個流程, 因此我用假的進度來模擬整個步驟。
首先建立一個專案, 剛開始只是一個很簡單的Activity,
public class ProgressbarDemoActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_progressbar_demo);
}
}
接下來就是建立我們的AsyncTask,
從官網的範例可以知道,
http://developer.android.com/reference/android/os/AsyncTask.html
在這之前, 我們可以看到網站上說明,
必須先繼承AsyncTask,
private class MyTask extends AsyncTask<Void, Void, Void> { ... }
然後我們必須實作四個方法, 分別是
onPreExecute()
doInBackground(Params...)
onProgressUpdate(Progress...)
onPostExecute(Result)
而這四個方法傳入的參數, 必須和繼承AsyncTask後面的泛型型態是相同的,
先來解釋這四個方法的意義,
第一個方法onPreExecute()可以從名稱知道, 他是在進行一些初始化的工作。
第二個方法是doInBackground()會傳入一個參數, 這個參數的數量是不定的,
也就是說, 你可以傳入零到數個參數也不是問題, 從官網的例子來看,
當宣告這個類別的物件時候, 只要呼叫execute這個方法,
傳入你想下載的網址, 就可以開始使用它了。
new DownloadFilesTask().execute(url1, url2, url3);
官網的範例是傳入三個下載的位置。第三個方法是onProgressUpdate(), 它一樣會傳入一些參數, 也是不定數量的,
而這個方法通常是在執行onInBackground的時候, 才會去呼叫它,
只要執行publishProgress()這個方法,
就會呼叫onProgressUpdate(), 利用這個方法, 就可以讓程式顯示目前進度為何。
最後一個方法是onPostExecute(), 這個用來接收結果,
通常你在onProgressUpdate()回傳的結果, 就會當參數傳到這個方法,
不過你要注意型態, 才不會沒有傳入。
現在來看一下範例怎麼寫的。
public class TestAsyncTask extends AsyncTask<URL, Integer, String> {
private Context mContext;
private ProgressDialog mDialog;
public TestAsyncTask(Context mContext) {
this.mContext = mContext;
}
protected void onPreExecute() {
mDialog = new ProgressDialog(mContext);
mDialog.setMessage("Loading...");
mDialog.setCancelable(false);
mDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
mDialog.show();
}
protected String doInBackground(URL... urls) {
// TODO Auto-generated method stub
int progress =0;
while(progress<=100){
try {
Thread.sleep(50);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
publishProgress(Integer.valueOf(progress));
progress++;
}
return "ok";
}
@Override
protected void onProgressUpdate(Integer... progress) {
// TODO Auto-generated method stub
mDialog.setProgress(progress[0]);
}
protected void onPostExecute(String result) {
if(result.equals("ok")){
mDialog.dismiss();
}
}
}
我用顏色將傳入的參數, 與泛型的參數對應起來,這樣就可以很清楚知道哪些參數是什麼功用,
雖然從型態就可以了解是如何對應的,
但是萬一我們的型態設定為相同的話, 有可能會造成錯亂,
所以還是了解一下位置比較妥當。
protected void onPreExecute() {
mDialog = new ProgressDialog(mContext);
mDialog.setMessage("Loading...");
mDialog.setCancelable(false);
mDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
mDialog.show();
}
一開始先加入一個ProgressbarDialog用來計算我們的進度,
紅色那行一定要加入, 這樣才可以看到進度。
protected String doInBackground(URL... urls) {
// TODO Auto-generated method stub
int progress =0;
while(progress<=100){
try {
Thread.sleep(50);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
publishProgress(Integer.valueOf(progress));
progress++;
}
return "ok";
}
為了模擬檔案傳輸速度, 所以故意設定0.05秒就睡一下,這樣才不會一下子就跑完了,
這邊可以參考官網真正的下載檔案, 然後設定progressbar的進度。
@Override
protected void onProgressUpdate(Integer... progress) {
// TODO Auto-generated method stub
mDialog.setProgress(progress[0]);
}
呼叫publishProgress方法就會自動去呼叫onProgressUpdate方法,然後利用ProgressbarDialog的方法去設定進度。
protected void onPostExecute(String result) {
if(result.equals("ok")){
mDialog.dismiss();
}
}
當onInBackground結束, 並且return結果的時候, 就會呼叫onPostExecute方法,這時候我們將dialog消滅, 就可以回到原本的畫面了。
public class ProgressbarDemoActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_progressbar_demo); new TestAsyncTask(this).execute();
}
}
記得加上這一行, 才能呼叫AsyncTask類別。程式碼
http://uploadingit.com/file/r6oanakevrc0onmm/ProgressBarDemo.zip