AndroidGUI06:ProgressBar的常用技巧

来源:互联网 发布:工业三维动画软件 编辑:程序博客网 时间:2024/05/17 04:51

ProgressBar 有两种主要的形态:一个是圆形的,一个是长条形的,形如:

 

圆形的 ProgressBar ,通常用于未确定的何时结束的进度显示,它会一直显示动画。

长条形的 ProgressBar ,通常用于进度明确的进度显示。

 

1.     在布局文件 (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/progress_bar1"

                   style = "?android:attr/progressBarStyleSmall"                                          <!-- 小圆 ProgressBar -->

                   android:layout_width = "wrap_content"

                   android:layout_height = "wrap_content"

         />

        

         < ProgressBar

                   android:id = "@+id/progress_bar2"                                                             <!-- 缺省地,是中圆 ProgressBar -->

                   android:layout_width = "wrap_content"

                   android:layout_height = "wrap_content"

         />

        

         < ProgressBar

                   android:id = "@+id/progress_bar3"

                   style = "?android:attr/progressBarStyleLarge"                                          <!-- 大圆 ProgressBar -->

                   android:layout_width = "wrap_content"

                   android:layout_height = "wrap_content"

         />

        

         < ProgressBar

                   android:id = "@+id/progress_bar4"

                   style = "?android:attr/progressBarStyleHorizontal"                                  <!-- 长条形 ProgressBar -->

                   android:layout_width = "fill_parent"

                   android:layout_height = "8sp"                                                                      <!-- 指明高度为 8sp-->

                   android:max = "100"                                                                                      <!-- 最大值为 100 -->

         />

        

         < TextView                                                                                                                  <!-- 此 TextView 做分隔符用 -->

                   android:layout_width = "fill_parent"

                   android:layout_height = "6sp"

         />

        

         < ProgressBar

                   android:id = "@+id/progress_bar5"

                   style = "?android:attr/progressBarStyleHorizontal"

                   android:layout_width = "fill_parent"

                   android:layout_height = "wrap_content"

                   android:max = "100"

         />

        

         < Button                                                                                                           <!-- 用于触发进度条相关操作 –>

                   android:id = "@+id/button"

                   android:layout_width = "wrap_content"

                   android:layout_height = "wrap_content"

                   android:text = " 进度条测试 "

         />

</ LinearLayout >

 

对应的界面结果显示如下:

 

2.     通过程序的方式,我们还可以把进度条放到应用的标题栏 (Title bar) 中。这个可以用程序来实现:

    requestWindowFeature(Window. FEATURE_INDETERMINATE_PROGRESS );          // 在 Titlebar 中,放置圆形进度条

    requestWindowFeature(Window. FEATURE_PROGRESS );                                             // 在 Titlebar 中,放置长条形进度条

    setContentView(R.layout. main );

       

    setProgressBarIndeterminateVisibility( true );                                                                       // 在 Titlebar 中,显示圆形进度条

    setProgressBarVisibility( true );                                                                                                // 在 Titlebar 中,显示长条形进度条

 

         注意: requestWindowFeature 方法的调用,必须在 setContentView 之前!

 

3.     Activity 所对应的代码:

public class ControlProgressBar extends Activity

implements

OnClickListener

{

         // 声明 5 个 ProgressBar 对象

         private ProgressBar progress_bar1 ;

         private ProgressBar progress_bar2 ;

         private ProgressBar progress_bar3 ;

         private ProgressBar progress_bar4 ;

         private ProgressBar progress_bar5 ;

         // 声明一个 Button 对象

         private Button button ;

         // 声明一个 Handler 对象

         private Handler progressHandler ;

        

    @Override

    public void onCreate(Bundle savedInstanceState)

    {

           super .onCreate(savedInstanceState);

           requestWindowFeature(Window. FEATURE_INDETERMINATE_PROGRESS );

// 在应用的 Title bar 上放置圆形 ProgressBar

          

requestWindowFeature(Window. FEATURE_PROGRESS );                        

// 在应用的 Title bar 上放置条形 ProgressBar

          

setContentView(R.layout. main );                                             

// requestWindowFeature 方法的调用必须在 setContentView 之前

       

           setProgressBarIndeterminateVisibility( true );              // 在应用的 Title bar 上显示圆形 ProgressBar

           setProgressBarVisibility( true );                                       // 在应用的 Title bar 上显示条形 ProgressBar

       

           // 获取 ProgressBar 对象

           progress_bar1 = (ProgressBar)findViewById(R.id. progress_bar1 );

           progress_bar2 = (ProgressBar)findViewById(R.id. progress_bar2 );

           progress_bar3 = (ProgressBar)findViewById(R.id. progress_bar3 );

           progress_bar4 = (ProgressBar)findViewById(R.id. progress_bar4 );

           progress_bar5 = (ProgressBar)findViewById(R.id. progress_bar5 );

       

           // 获取 Handler 对象

           progressHandler = new Handler()

             {

                        @Override

                        public void handleMessage(Message msg)      // 重写 handleMessage 方法

                        {

                                 setProgress(msg. what * 100);                     // 设定 Title bar 上的条形和圆形 ProgressBar 的进度 , 缺省地 ,

                                                                                                            // 他们的最大值为 10000 ,为此,由于我们准备的 msg.what 的取值

                                                                                                            // 范围为 0 ~ 100 ,因此,在这里需要乘以 100 。

                                                                                                            // 另外需要注意的是,当 Title bar 上的 ProgressBar 达到最大值

                                                                                                            // 后,他们会自行消失

                       

                                 progress_bar4 .setProgress(msg. what );    // 根据 msg.what 的取值 , 设定 progress_bar4 的进度                                     

                       

                                 progress_bar5 .setProgress(msg. what );   

// 根据 msg.what 的取值 , 设定 progress_bar5 的进度

                                 progress_bar5 .setSecondaryProgress(( int )(Math.sqrt (msg. what )) * 10);

                                     // 根据 msg.what 的取值,设定 progress_bar5 的第二个进度

                       

                                 if (msg. what == 100)                                      // 达到最大值后 , 让 progress_bar4 不可见

                                 {

                                          progress_bar4 .setVisibility(ProgressBar. INVISIBLE );

                                 }

                        }                

             };

       

             // 获取 Button 对象 , 并为其设置 OnClickListener

           button = (Button)findViewById(R.id. button );

           button .setOnClickListener( this );

    }

 

         public void onClick(View v)

         {

                   progress_bar1 .setVisibility(ProgressBar. VISIBLE );                     // progress_bar1 继续可见

                   progress_bar2 .setVisibility(ProgressBar. GONE );                         // progress_bar2 不可见 , 且离开界面

                   progress_bar3 .setVisibility(ProgressBar. INVISIBLE );                  // progress_bar3 不可见 , 但依然在界面上

                   ProgressThread pt = new ProgressThread( progressHandler ); // 创建线程 pt

                   pt.start();                                                                                                 // 启动线程 pt

         }

}

 

class ProgressThread extends Thread

{

         private Handler handler ;

         public ProgressThread(Handler handler)                                               // 传入一个 Handler 对象

         {

                   this . handler = handler;

         }

        

         @Override

         public void run()

         {

                   int i = 0;

                   while (i <= 100)

                   {

                            handler .sendEmptyMessage(i);                                             // i 就是 Message 中 what 的值 ,handler.sendEmptyMessage

                                                                                                                         // 会触发 handler 的 handleMessage 执行

                            ++i;

                            try

                            {

                                     sleep (100);                                                               // 休息 100ms

                            }

                            catch (InterruptedException e)

                            {

                                     e.printStackTrace();

                            }

                   }

         }

}

 

运行结果:

在点击按钮之前:

 

点击按钮后:

 

达到最大值后:

 

4.     关于 Only the original thread that created a view hierarchy can touch its views 错误

在 Android 编程中,使用 Thread 更新 ProgressBar 的进度的时候,很多人都碰到过类似的问题。最好的解决办法就是类似 3中所给出的代码。  

 

5.     在上面的代码中,我们知道,所有的 ProgressBar 对象,都是在 Activity ControlProgressBar 中创建的,因此,对于这些ProgressBar 的更新工作,就必须要在 ControlProgressBar 这个 Activity 中完成 ( 在这个例子中,是该应用的主线程 ) ,而不能在另外一个线程中来完成对那些 ProgressBar 的状态更新。否则,就会出现“ Only the original thread that created a view hierarchy can touch its views ”这样的错误,从而使整个应用被 Forced Close 。

 

在上面的代码中,在 onClick 方法里面,我们新创建了一个 ProgressThread 的线程,在这个线程中,并没有直接去更新各个ProgressBar 的状态,只是通过一个循环,不断产生 Message.what ,并通过 sendMessage 方法,向 progressHandler 发送消息,并触发 progressHandler 中的 handleMessage 方法的执行。很显然 progressHandler 是在 Activity ControlProgressBar 中创建的,它本身也并没有创建新的线程,而在 handleMessage 方法中,我们对各个 ProgressBar 对象的状态,进行了更新。

 

 

类似下面的代码,试图在另外一个线程中改变主线程中界面元素的状态,就会出现“ Only the original thread that created a view hierarchy can touch its views ”这样的错误:

public class ControlProgressBar extends Activity

implements

OnClickListener

{

         // 声明 5 个 ProgressBar 对象       

// … …

         // 声明一个 Button 对象

         private Button button ;

        

    @Override

    public void onCreate(Bundle savedInstanceState)

    {

           super .onCreate(savedInstanceState);

           requestWindowFeature(Window. FEATURE_INDETERMINATE_PROGRESS );

           requestWindowFeature(Window. FEATURE_PROGRESS );                        

           setContentView(R.layout. main );

       

           setProgressBarIndeterminateVisibility( true );

           setProgressBarVisibility( true );

       

           // 获取 ProgressBar 对象

                   // … …        

       

             // 获取 Button 对象 , 并为其设置 OnClickListener

           button = (Button)findViewById(R.id. button );

           button .setOnClickListener( this );

    }

 

         public void onClick(View v)

         {

                   ProgressThread pt = new ProgressThread( this );       // 创建线程 pt

                   pt.start();                                                                              // 启动线程 pt

         }

}

 

 

class ProgressThread extends Thread

{

         private Context ctx ;

         public ProgressThread(Context ctx)                                      // 传入一个 Context 对象 ( 实参将是 ControlProgressBar )

         {

                   this . ctx = ctx;

         }

        

         @Override

         public void run()

         {

                   int i = 0;

                   while (i <= 100)

                   {

                            setProgress(i* 100);                                               

// 在本线程中 , 更新主线程中界面元素 Title bar 上的 ProgressBar 的状态 ,就会出现:

// “ Only the original thread that created a view hierarchy can touch its views ”这样的错误

                            ++i;

                            try

                            {

                                     sleep (100);                                                      // 休息 100ms

                            }

                            catch (InterruptedException e)

                            {

                                     e.printStackTrace();

                            }

                   }

         }

}

 

 

6.     形如下面的代码,不会报错,但会阻塞 ProgressBar 对象的状态更新,因此也不是好办法。可惜网上很多人似乎在推荐这种方式,实有误人之嫌。

final Handler handler= new Handler(); 

 

final Runnable runnable = new Runnable()

              public void run()

              { 

                   // 更新界面元素  

              } 

         }; 

 

private OnClickListener btnLisener = new OnClickListener()

              public void onClick(View v)

              { 

                   requestData(); 

              } 

}; 

 

protected void requestData()

              Thread t = new Thread()

              { 

                    public void run()

                   { 

                        handler.post(runnable);

// 加入到消息队列这样没有启动新的线程 , 虽然没有报异常 , 但仍然阻塞 ProgressBar 的进度显示  

                   } 

              }; 

              t.start(); 

}

原创粉丝点击