2014年1月10日

在 Android 用ProgressBar顯示下載圖片的進度

最近寫了一個下載圖片的程式,但當時卻沒考慮到下載進度的顯示,要是圖檔很大的時侯,程式可能就會畫面停格,使用者也會一頭霧水。後來我把ProgressBar這個元件拿進來用,我想在按下按鈕後,可以進行圖檔下載,並顯示ProgressBar,當下載完畢後就隱藏ProgressBar,並把下載完成的圖片顯示在畫面上。

ProgressBar根據Style區分為四種,其中三種是轉圈圈的動態圖示,另一種是長型的進度條。

以下就是一個轉圈圈的ProgressBar

<ProgressBar
 android:id="@+id/progressBar1"
 style="?android:attr/progressBarStyleLarge"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"/>


根據畫面大小顯示位置,開發者可以自行設定為大型、中型還是小型的圖示
style="?android:attr/progressBarStyleLarge" 大型尺寸
style="?android:attr/progressBarStyleSmall" 小型尺寸
若沒有填寫,則預設為中型尺寸,也可以用
style="?android:attr/progressBarStyleMiddle" 來表示。

而橫條則是 style="?android:attr/progressBarStyleHorizontal"

activity_main.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity" >

 <Button
    android:id="@+id/buttonClick"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:text="按我下載圖片"/>       

 <ImageView
     android:id="@+id/ivImage"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:layout_below="@+id/buttonClick"
     android:layout_marginTop="20dp"
     android:visibility="gone" />

 <ProgressBar
    android:id="@+id/progressBar1"
    style="?android:attr/progressBarStyleLarge"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignLeft="@+id/buttonClick"
    android:layout_alignRight="@+id/buttonClick"
    android:layout_below="@+id/buttonClick"
    android:layout_marginTop="20dp"
    android:visibility="gone" />
</RelativeLayout>



MainActivity

 private Button btnClick;
 private ProgressBar progressbar1;
 private ImageView imageView;
 private String urlPath = "";
 private String[] urls = {"https://fbcdn-sphotos-a-a.akamaihd.net/hphotos-ak-frc3/1477341_10151905232591588_655832224_n.png",
                          "https://fbcdn-sphotos-g-a.akamaihd.net/hphotos-ak-prn1/t1/29552_10151712215411588_739185948_n.png",
                          "https://fbcdn-sphotos-h-a.akamaihd.net/hphotos-ak-prn1/t1/73998_10151252154266588_140103885_n.png"};
 private byte[] data = null;
 private int loadindex = 0;

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

      btnClick = (Button) findViewById(R.id.buttonClick);
      progressbar1 = (ProgressBar) findViewById(R.id.progressBar1);
      imageView = (ImageView) findViewById(R.id.ivImage);

      btnClick.setOnClickListener(new OnClickListener() {

           @Override
           public void onClick(View v) {
                btnClick.setClickable(false);
                if(loadindex==urls.length){
                     loadindex = 0;
                }
                urlPath = urls[loadindex];
                loadindex++;                   
                data = null;
                progressbar1.setVisibility(View.VISIBLE);
                imageView.setVisibility(View.GONE);

                Thread thread = new Thread(new Runnable() {
                     public void run() {
                          try {
                               data = loadData();

                          } catch (Exception e) {
                               // TODO Auto-generated catch block
                               e.printStackTrace();
                          }

                          runOnUiThread(new Runnable() {
                               public void run() {
                                    progressbar1.setVisibility(View.GONE);

                                    Bitmap bm = BitmapFactory.decodeByteArray(data, 0, data.length);
                                    imageView.setImageBitmap(bm);
                                    imageView.setVisibility(View.VISIBLE);
                                    btnClick.setClickable(true);
                               }
                          });
                     }
                });
                thread.start();
           }
      });

 }

 private byte[] loadData() throws Exception {

      InputStream inputstream;
      URL url = new URL(urlPath);
      HttpURLConnection conn = (HttpURLConnection) url.openConnection();
      inputstream = conn.getInputStream();
      ByteArrayOutputStream outputstream = new ByteArrayOutputStream();
      byte[] buffer = new byte[1024];
      int len = -1;
      while ((len = inputstream.read(buffer)) != -1) {
           outputstream.write(buffer, 0, len);
      }
      inputstream.close();
      outputstream.close();
      return outputstream.toByteArray();

 }



因為會下載Internet圖片,所以在AndroidManifest.xml 要加入這行設定。

<uses-permission android:name="android.permission.INTERNET" />



這樣就可以達到下載圖片時顯示ProgressBar,但是繞圈圈可能不是我們想要的,看起來是有點弱掉了,我也想要像"賴"在下載圖片時有橫條式的PROGRESSBAR和下載大小文字顯示。

首先先更改progressbar的style,我順便改了一下顯示寬度。

activity_main.xml

<ProgressBar
    android:id="@+id/progressBar1"
    style="?android:attr/progressBarStyleHorizontal"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"/>



執行結果後,蛤~ 不會動。

原來橫條ProgressBar 是要先設定初始值,要動態顯示進度條就要設定值給它。

activity_main.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity" >

<Button
    android:id="@+id/buttonClick"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:text="按我下載圖片" />

<ImageView
    android:id="@+id/ivImage"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_below="@+id/buttonClick"
    android:layout_marginTop="20dp"
    android:visibility="gone" />

<ProgressBar
    android:id="@+id/progressBar1"
    style="?android:attr/progressBarStyleHorizontal"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_alignLeft="@+id/buttonClick"
    android:layout_alignRight="@+id/buttonClick"
    android:layout_below="@+id/buttonClick"
    android:layout_marginTop="20dp"
    android:visibility="gone" />

<TextView
    android:id="@+id/progressText"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_alignLeft="@+id/buttonClick"
    android:layout_alignRight="@+id/buttonClick"
    android:layout_below="@+id/progressBar1"
    android:layout_marginTop="20dp"
    android:gravity="center" />

</RelativeLayout>



MainActivity

 protected static final int PROGRESS = 0x10000;

 private Button btnClick;
 private ProgressBar progressbar1;
 private TextView progressText;
 private ImageView imageView;

 private String urlPath = "";
 private String[] urls = {
           "https://fbcdn-sphotos-a-a.akamaihd.net/hphotos-ak-frc3/1477341_10151905232591588_655832224_n.png",
           "https://fbcdn-sphotos-g-a.akamaihd.net/hphotos-ak-prn1/t1/29552_10151712215411588_739185948_n.png",
           "https://fbcdn-sphotos-h-a.akamaihd.net/hphotos-ak-prn1/t1/73998_10151252154266588_140103885_n.png" };
 private byte[] data = null;
 private int loadindex = 0;

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

      btnClick = (Button) findViewById(R.id.buttonClick);
      progressbar1 = (ProgressBar) findViewById(R.id.progressBar1);
      progressText = (TextView) findViewById(R.id.progressText);
      imageView = (ImageView) findViewById(R.id.ivImage);

      btnClick.setOnClickListener(new OnClickListener() {

           @Override
           public void onClick(View v) {

                btnClick.setClickable(false);
                if (loadindex == urls.length) {
                     loadindex = 0;
                }
                urlPath = urls[loadindex];
                loadindex++;
                data = null;
                progressbar1.setVisibility(View.VISIBLE);

                progressbar1.setMax(100); // 設定最大值是100
                progressbar1.setProgress(0); // 設定目前進度0
                progressText.setText("");
                progressText.setVisibility(View.VISIBLE);
                imageView.setVisibility(View.GONE);

                Thread thread = new Thread(new Runnable() {
                     public void run() {
                          try {
                               data = loadData();

                          } catch (Exception e) {
                               // TODO Auto-generated catch block
                               e.printStackTrace();
                          }

                          runOnUiThread(new Runnable() {
                               public void run() {
                                    progressbar1.setVisibility(View.GONE);
                                    progressText.setVisibility(View.GONE);
                                    Bitmap bm = BitmapFactory.decodeByteArray(data,
                                              0, data.length);
                                    imageView.setImageBitmap(bm);
                                    imageView.setVisibility(View.VISIBLE);
                                    btnClick.setClickable(true);
                               }
                          });
                     }
                });
                thread.start();
           }
      });

 }

 private byte[] loadData() throws Exception {

      InputStream inputstream;
      URL url = new URL(urlPath);
      HttpURLConnection conn = (HttpURLConnection) url.openConnection();
      inputstream = conn.getInputStream();
      ByteArrayOutputStream outputstream = new ByteArrayOutputStream();
      byte[] buffer = new byte[1024];
      int len = -1;

      int totalSize = conn.getContentLength();
      int downloadSize = 0;

      while ((len = inputstream.read(buffer)) != -1) {
           outputstream.write(buffer, 0, len);
           downloadSize = downloadSize + len;

           Message msg = new Message();
           msg.what = PROGRESS;
           msg.arg1 = totalSize;
           msg.arg2 = downloadSize;
           mHandler.sendMessage(msg);

      }
      inputstream.close();
      outputstream.close();
      return outputstream.toByteArray();

 }

 //設定ProgressBar進度
 private Handler mHandler = new Handler() {
      public void handleMessage(Message msg) {

           switch (msg.what) {
           case PROGRESS:

                int total = msg.arg1;
                int current = msg.arg2;
                Log.i("progress:", current + "/ " + total);

                int count = current * 100 / total;

                progressbar1.setProgress(count);
                progressText.setText(current + "/" + total);
                break;
           }
      }
 };


加上ProgressBar處理的部份,這時下載橫條ProgressBar也能顯示進度,再輔助下載大小文字顯示,這樣一來效果更親民了,打完收工。