ZetCode

Android ProgressBar 小部件

最后修改于 2012 年 11 月 29 日

在本章 Android 开发教程中,我们将介绍 ProgressBar 小部件。ProgressBar 是一个直观显示某个任务进度的小部件。该小部件有两种基本模式:圆形进度条和水平进度条。

我们将通过两个示例来演示它们。

ProgressBar I

我们有一个水平 ProgressBar 小部件和一个 TextView 小部件,用于显示任务完成的百分比。清单文件保持不变。

main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
<ProgressBar 
    android:id="@+id/pbId"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    style="?android:attr/progressBarStyleHorizontal"
    android:layout_margin="10dp"
    />       
<TextView
    android:id="@+id/tvId"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:layout_margin="10dp"
    />
</LinearLayout>

main.xml 布局文件中,我们有一个 ProgressBar 和一个 TextViewstyle="?android:attr/progressBarStyleHorizontal" 样式使 ProgressBar 成为水平样式。ProgressBar 的默认模式是圆形模式。

strings.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="app_name">ProgBar</string>
</resources>

字符串资源文件。

MainActivity.java
package com.zetcode.progbar2;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.util.Log;


public class MainActivity extends Activity
{
    ProgressBar pb;
    TextView tv;
    int prg = 0;

    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        pb = (ProgressBar) findViewById(R.id.pbId);
        tv = (TextView) findViewById(R.id.tvId);
 
        new Thread(myThread).start();
    }

    private Runnable myThread = new Runnable()
    { 
        @Override
        public void run() 
        {
            while (prg < 100)
            {
                try
                {
                    hnd.sendMessage(hnd.obtainMessage());
                    Thread.sleep(100);
                }
                catch(InterruptedException e) 
                {  
                    Log.e("ERROR", "Thread was Interrupted");
                }
            }

            runOnUiThread(new Runnable() { 
                public void run() {
                    tv.setText("Finished");
                }
            });          
        }
    
        Handler hnd = new Handler()
        {    
            @Override
            public void handleMessage(Message msg) 
            {
                prg++;
                pb.setProgress(prg);

                String perc = String.valueOf(prg).toString();
                tv.setText(perc+"% completed");
            }
        };
    };
}

我们创建一个线程来控制 ProgressBar 的进度。

new Thread(myThread).start();

启动了一个新线程。在 Android 中,耗时任务应该在线程中执行,以防止应用程序看起来无响应。线程通过从其 main() 方法返回或通过异常来结束。

@Override
public void run() 
{
    while (prg < 100)
    {
        try
        {
            hnd.sendMessage(hnd.obtainMessage());
            Thread.sleep(100);
        }
        catch(InterruptedException e) 
        {  
            Log.e("ERROR", "Thread was Interrupted");
        }
    }

    runOnUiThread(new Runnable() { 
        public void run() {
            tv.setText("Finished");
        }
    });          
}

线程中的代码放在 run() 方法中。我们将通过调用 Thread.sleep() 方法来模拟耗时任务。这迫使我们处理 InterruptedException。Android 应用程序运行在单线程模型中。主活动的所有组件都在主线程中创建。这些组件不能在其他线程中进行操作。为了解决这个问题,我们使用 Handler 对象或调用 runOnUiThread() 方法。

runOnUiThread(new Runnable() { 
    public void run() {
        tv.setText("Finished");
    }
});   

只有创建视图层次结构的原始线程才能触及其视图。在这里,我们正在修改 TextView 小部件。因此,我们将代码放入 runOnUiThread() 方法中,该方法在创建小部件的主 UI 线程中执行代码。

Handler hnd = new Handler()
{    
    @Override
    public void handleMessage(Message msg) 
    {
        prg++;
        pb.setProgress(prg);

        String perc = String.valueOf(prg).toString();
        tv.setText(perc+"% completed");
    }
};

从另一个线程操作小部件的另一种方法是使用 Handler 对象。它用于将操作排队,以便在与自身不同的线程上执行。我们更新进度条并设置已完成任务的百分比到文本视图。

ProgressBar widget
图:ProgressBar 小部件

ProgressBar II

在第二个示例中,我们展示了 ProgressBar 在圆形模式下的用法。清单文件无需修改。

main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
<ProgressBar 
    android:id="@+id/pbId"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    />    
<TextView
    android:id="@+id/tvId"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:text="@string/msg"
    />        
</LinearLayout>

main.xml 文件中,我们有一个 ProgressBar 和一个 TextViewProgressBar 具有默认样式,即圆形样式。这等同于使用了 style="?android:attr/progressBarStyle" 属性。

strings.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="app_name">CirProgBar</string>
    <string name="msg">Please wait...</string>
</resources>

我们在 strings.xml 文件中有两个字符串资源。

MainActivity.java
package com.zetcode.progbar;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.view.View;
import android.util.Log;

public class MainActivity extends Activity
{
    ProgressBar pb;
    TextView tv;
    int prg = 0;

    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        pb = (ProgressBar) findViewById(R.id.pbId);
        tv = (TextView) findViewById(R.id.tvId);
 
        new Thread(myThread).start();
    }

    private Runnable myThread = new Runnable()
    { 
        @Override
        public void run() 
        {
            while (prg < 100)
            {
                try
                {
                    hnd.sendMessage(hnd.obtainMessage());
                    Thread.sleep(100);
                }
                catch(InterruptedException e) 
                {  
                    Log.e("ERROR", "Thread was Interrupted");
                }
            }

            runOnUiThread(new Runnable() { 
                public void run() {
                    tv.setText("Finished");
                    pb.setVisibility(View.GONE); 
                }
            });          
        }
    
        Handler hnd = new Handler()
        {    
            @Override
            public void handleMessage(Message msg) 
            {
                prg++;
                pb.setProgress(prg);
            }
        };
    };
}

代码与第一个示例类似,但有一些修改。

runOnUiThread(new Runnable() { 
    public void run() {
        tv.setText("Finished");
        pb.setVisibility(View.GONE); 
    }
}); 

任务完成后,我们使用 setVisibility() 方法隐藏 ProgressBar。圆本身是无限动画,因此在任务完成后,我们需要隐藏该小部件。

Circular ProgressBar widget
图:圆形 ProgressBar 小部件

在本章 Android 开发教程中,我们提到了 ProgressBar 小部件。