ProgressDialog是AlertDialog的子類,我們用它來顯示有進度條的Dialog。這種帶有進度的UI控制項在好多UI架構中都可以看到,當使用者執行一個操作時間較長的操作時,在一個設計良好的系統中應該要顯示一個進度條提示使用者目前處理的進度到哪了。在安裝應用程式和網路互動應用中最常見到進度條,安裝應用程式由於耗時間長度,所以需要指示使用者進度,網路互動由於網路環境的不穩定也需要指示使用者互動的進度(尤其是當你在上傳或下載大檔案時)。所以進度條是一個很常用到的控制項。
Android為我們提供了一個很好用的內建處理進度條的Dialog,它就是ProgressDialog。ProgressDialog裡的進度條分為兩種:可確定值進度條和不可確定值進度條。可確定值進度條是指:系統能指示目前進度值,需要更新目前進度條的值,如果進度條到達一定值就表示完成進度。不可確定值進度條是指:系統指示需要等待,但是沒有給出目前進度,所以你無法得知目前進度到哪裡,只是能看到系統在處理,還需要等待的介面,所以說它沒有一個確定值。
我們來看一個最簡單的顯示ProgressDialog的代碼:
ProgressDialog.show(this, "正在載入...", "系統正在處理您的請求");
上面代碼直接顯示了一個ProgressDialog,它是屬於不可確定值進度條的ProgressDialog,它的參數很簡單第一個參數是Context上下文資訊,第二個參數是Dialog的title標題,第三個參數則是Dialog的body要顯示的資訊,代碼的效果如下:
可以看到ProgressDialog顯示了一個在轉動的小圓圈,這個小圓圈將會永久轉動直到Dialog消失掉,所以這是一個不可確定值的進度條。運行代碼我們發現這個Dialog不可取消掉,它會一直存在直到你用代碼控制讓dialog消失,所以它是不可取消的,如果要讓使用者可以取消,要再後面添加兩個參數,分別是:
ProgressDialog.show(this,<br /> "正在載入...", //標題<br /> "系統正在處理您的請求", //內容<br /> true, //是否不可確定值<br /> true);
上面使用show方法建立的不可確定值的ProgressDialog比較簡單,如果要建立一個可確定值的進度條dialog就會比較麻煩,因為你需要編寫一些額外的代碼來控制進度條。這邊建立ProgressDialog就需要通過new 建立一個新對象,它沒有Builder可以通過配置來產生。所以我們要做的就是:
- 建立ProgressDialog對象
- 設定它內部的進度條是可確定值的
- 將它顯示出來
- 更新進度條值,當進度完成後隱藏對話方塊
我們根據上面這幾步,建立一個可複用的可確定值的ProgressDialog。首先我們要給需要managed的Dialog分配一個id值,然後重寫onCreateDialog方法建立ProgressDialog。
@Override<br />protected Dialog onCreateDialog(int id) {</p><p> switch(id){</p><p> case PROGRESS_DIALOG :<br /> ProgressDialog pd = new ProgressDialog(this);<br /> pd.setTitle("進度條"); //設定標題<br /> pd.setMessage("正在處理請稍後..."); //設定body資訊<br /> pd.setMax(100); //進度條最大值是100<br /> pd.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); //設定進度條樣式是 橫向的</p><p> return pd;</p><p> }</p><p> return super.onCreateDialog(id);<br />}
在這裡我們重寫Activity的onCreateDialog方法,讓ProgressDialog變成是可複用的managed dialog。當點擊按鈕時我們調用:
showDialog(PROGRESS_DIALOG);
將onCreateDialog方法裡建立的ProgressDialog對象顯示出來:
上面就是可確定值進度條ProgressDialog的效果,可是它的進度條不會動,這是因為你還沒用代碼去控制進度條的進度,所以這邊我們需要編寫一些額外代碼,當表單顯示時首先讓進度條歸零,然後用一個線程讓進度條每100ms增加1,所以總共要10秒才能讀完整個進度條。我們用Handler對象來處理,因為android中使用的是UI單線程模式,你自己建立線程不能訪問UI控制項,否則會拋出異常。而Handler會將需要執行的代碼放到UI線程去執行。所以我們先定義一個Handler內部類來改變進度條的值。
private static final int PROGRESS_DIALOG = 1;</p><p>int progressValue = 0; //儲存進度條目前的進度值,當達到最大值時隱藏ProgressDialog<br />ProgressDialog mProgressDialog ; //引用的ProgressDialog對象<br />Handler progressHandler;</p><p>@Override<br />protected void onCreate(Bundle savedInstanceState) {<br /> super.onCreate(savedInstanceState);</p><p> setContentView(R.layout.dialog3);</p><p> progressHandler = new Handler(){</p><p> public void handleMessage(android.os.Message msg) {</p><p> if(progressValue == 100){<br /> mProgressDialog.dismiss();<br /> }else{<br /> //設定進度條的值加1<br /> progressValue ++;<br /> mProgressDialog.incrementProgressBy(1);<br /> //如果進度條還沒結束則100ms後進度條加1,迴圈調用每100ms就將進度條加1<br /> progressHandler.sendEmptyMessageDelayed(0, 100);<br /> }</p><p> };</p><p> };</p><p>}
然後添加按鈕事件,當使用者點擊顯示可確定值ProgressDialog時,首先將進度條清0,然後發送第一條開始更新進度條的handler訊息,因為handler訊息處理方法內部有迴圈調用發送訊息,所以只要第一次觸發程式就會每100ms發送一個更新訊息,直到進度條值到達100,隱藏掉對話方塊。所有代碼如下:
<?xml version="1.0" encoding="utf-8"?><br /><LinearLayout<br /> xmlns:android="http://schemas.android.com/apk/res/android"<br /> android:orientation="vertical"<br /> android:layout_width="fill_parent"<br /> android:layout_height="fill_parent"></p><p> <Button<br /> android:layout_width="wrap_content"<br /> android:layout_height="wrap_content"<br /> android:text="顯示最簡單的ProgressDialog"<br /> android:onClick="onClick1"<br /> /></p><p> <Button<br /> android:layout_width="wrap_content"<br /> android:layout_height="wrap_content"<br /> android:text="顯示可確定值的ProgressDialog"<br /> android:onClick="onClick2"<br /> /></p><p></LinearLayout>
package com.king.dialog.uicontroller.dialog;</p><p>import com.king.dialog.uicontroller.R;</p><p>import android.app.Activity;<br />import android.app.Dialog;<br />import android.app.ProgressDialog;<br />import android.os.Bundle;<br />import android.os.Handler;<br />import android.view.View;</p><p>public class ProgressDialogActivity extends Activity {</p><p> private static final int PROGRESS_DIALOG = 1;</p><p> int progressValue = 0; //儲存進度條目前的進度值,當達到最大值時隱藏ProgressDialog<br /> ProgressDialog mProgressDialog ; //引用的ProgressDialog對象<br /> Handler progressHandler;</p><p> @Override<br /> protected void onCreate(Bundle savedInstanceState) {<br /> super.onCreate(savedInstanceState);</p><p> setContentView(R.layout.dialog3);</p><p> progressHandler = new Handler(){</p><p> public void handleMessage(android.os.Message msg) {</p><p> if(progressValue == 100){<br /> mProgressDialog.dismiss();<br /> }else{<br /> //設定進度條的值加1<br /> progressValue ++;<br /> mProgressDialog.incrementProgressBy(1);<br /> //如果進度條還沒結束則100ms後進度條加1,迴圈調用每100ms就將進度條加1<br /> progressHandler.sendEmptyMessageDelayed(0, 100);<br /> }</p><p> };</p><p> };</p><p> }</p><p> public void onClick1(View view){</p><p> ProgressDialog.show(this,<br /> "正在載入...", //標題<br /> "系統正在處理您的請求", //內容<br /> true, //是否不可確定值<br /> true); // 是否可取消<br /> }</p><p> @Override<br /> protected Dialog onCreateDialog(int id) {</p><p> switch(id){</p><p> case PROGRESS_DIALOG :<br /> mProgressDialog = new ProgressDialog(this);<br /> mProgressDialog.setTitle("進度條"); //設定標題<br /> mProgressDialog.setMessage("正在處理請稍後..."); //設定body資訊<br /> mProgressDialog.setMax(100); //進度條最大值是100<br /> mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); //設定進度條樣式是 橫向的</p><p> return mProgressDialog;</p><p> }</p><p> return super.onCreateDialog(id);<br /> }</p><p> public void onClick2(View view){</p><p> showDialog(PROGRESS_DIALOG);<br /> progressValue = 0;<br /> mProgressDialog.setProgress(0);<br /> progressHandler.sendEmptyMessage(0);</p><p> }</p><p>}
代碼運行效果如下:
使用者可以看到在走動的進度條,當進度條達到100時ProgressDialog就自動消失。這邊一個痛點就是Handler的用法,這個以後會再仔細介紹,現在先瞭解Handler就是可以將代碼放到UI線程去執行即可。