AndroidGUI06:ProgressBar的常用技巧
2011-05-11 22:55
351 查看
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();
}
有两种主要的形态:一个是圆形的,一个是长条形的,形如:
圆形的
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();
}
相关文章推荐
- AndroidGUI06:ProgressBar的常用技巧
- AndroidGUI24:TabHost常用技巧
- android常用技巧
- android 常用技巧api
- Android安卓破解之逆向分析SO常用的IDA分析技巧
- Android自学笔记之ProgressBar进度条的属性、常用方法及使用
- Android编程规范与常用技巧
- AndroidGUI08:RatingBar的常用技巧
- android学习日记03--常用控件progressbar/seekbar
- 大话Android项目中的常用技巧
- Android 编程规范与常用技巧
- Android ViewTreeObserver的常用技巧
- AndroidGUI04:Button(Basic Button,ImageButton, Check Box, Toggle Button, Radio Button)的常用技巧
- Android常用控件之ProgressBar系列
- android input子系统之-常用命令及技巧
- Android 常用编程技巧
- AndroidGUI01:TextView的常用技巧
- # AndroidStudio 常用工具和使用技巧(持续更新)
- AndroidGUI13:ViewTreeObserver的常用技巧
- Android 常用技巧