【Android】进度条与线程之间的消息处理

有点没想到的是,这样的一个小小的程序弄了很久才做完。

这个程序看起来很简单的,如下图:

一个进度条在不断地增加,累加到超过100%,隐藏载入进度条,并且文字改变成一个“倒数3秒”继续执行。

数完三秒之后则继续进行进度条的累加。

首先,由于标签文本是动态的,通过Java文件控制,在res\values\string.xml,仅仅需要把程序名称改成“进度条”,没有什么特别的:

<?xml version="1.0" encoding="utf-8"?><resources><string name="app_name">进度条</string><string name="action_settings">Settings</string></resources>之后,布局也没有什么特别的,思想如下图:

在res\layout\activity_main.xml中,修改成如下代码即可:

<LinearLayout xmlns:android=""android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical" ><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="horizontal" ><ProgressBarandroid:id="@+id/ProgressBar1"style="@android:style/Widget.ProgressBar.Large"android:layout_width="wrap_content"android:layout_height="wrap_content" /><TextViewandroid:id="@+id/TextView1"android:layout_width="wrap_content"android:layout_height="wrap_content"/></LinearLayout><ProgressBarandroid:id="@+id/ProgressBar2"style="?android:attr/progressBarStyleHorizontal"android:layout_width="match_parent"android:layout_height="wrap_content"android:max="100" /></LinearLayout>其中,这里细长进度条ProgressBar2的style可能比较特别,但安卓是这样要求的没有办法,指定其最大值为100%。进度条1,看起来像是个不断旋转的载入图像,但其实也是进度条的一种,其没有最大值,也不能通过Java文件设置其当前进度,在MainActivity.Java中只能设定其显示与否。

这里为各个组件设置ID,同时使用了嵌套线性布局。

关键是MainActivity.java这个文件弄了我好久,代码如下:

package com.progressbar;import java.util.Timer;import java.util.TimerTask;import android.os.Bundle;import android.os.Handler;import android.os.Message;import android.app.Activity;import android.view.Menu;import android.view.View;import android.widget.ProgressBar;import android.widget.TextView;public class MainActivity extends Activity {private ProgressBar ProgressBar1;private ProgressBar ProgressBar2;private TextView TextView1;//定义一个消息处理器。private Handler handler;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);//获取各个组件,没有什么特别的。ProgressBar1 = (ProgressBar) findViewById(R.id.ProgressBar1);ProgressBar2 = (ProgressBar) findViewById(R.id.ProgressBar2);TextView1 = (TextView) findViewById(R.id.TextView1);//设置一个每隔1000毫秒,也就是1秒就运行一次的定时器new Timer().schedule(new TimerTask() {int i = 0;//这里代表进度int j = 3;//这里代表进度达100%时的倒数@Overridepublic void run() {Message msg = new Message();//这里的消息声明必须放在run()方法之中,否则程序,由于旧的消息不消亡会卡死//把Message的new方法,放在run()这里,定时器每一次重新执行,则会杀死旧信息,创建新的信息。if (i < 100) {msg.what = i;handler.sendMessage(msg);//将i存放到msg的what类成员中传给消息处理器i += Math.random() * 20;//i每次递增20*(0.xxx)的进度} else {if (j > 0) {msg.what = i;msg.arg1 = j;handler.sendMessage(msg);//将j放到msg的arg1类成员中传递给消息处理器j–;} else {//倒数完毕,重新开始i = 0;j = 3;}}}}, 0, 1000);//不停在接受定时器的消息,根据消息的参数,进行处理handler = new Handler(new Handler.Callback() {//这样写,就不弹出什么泄漏的警告了@Overridepublic boolean handleMessage(Message msg) {if (msg.what < 100) {//如果消息的 what参数少于100,则设置进度条ProgressBar2.setProgress(msg.what);//设置细长进度条ProgressBar2的进度if (msg.what == 0) {//仅仅是在what参数等于0的时候,设置标签文本与进度条,不要每次读取进度都加载。TextView1.setText("正在运行中……");ProgressBar1.setVisibility(View.VISIBLE);}} else {if (msg.arg1 == 3) {ProgressBar1.setVisibility(View.GONE);ProgressBar2.setProgress(0);}TextView1.setText("运行完毕,,等待" + msg.arg1 + "秒继续运行下一次的程序……");}return false;}});}@Overridepublic boolean onCreateOptionsMenu(Menu menu) {// Inflate the menu; this adds items to the action bar if it is present.getMenuInflater().inflate(R.menu.main, menu);return true;}}可能有人不解,为何不直接在定时器中设置文本,还要非常复杂的样子整个消息处理器Handle,又要处理器的泄露问题。

我最初也不像这样整的,全因为定时器是一条新的线程,安卓不允许在别的线程中设置标签文本TextView1的值,如果你不是在Android进程中设置标签文本的,则会弹出一下的错误提示:

因此,必须利用安卓在线程中的消息传递,让处于安卓的Original Thread来设置标签文本的值,对进度条进行处理。就这个东西搞了我很久。

同时,这里的定时器的设置使用了Java中的匿名内部类,具体见《【Java】定时器、线程与匿名内部类》(点击打开链接)。这里不赘述了。

最后随便说一句,这里的标签文本可以设置其TextSize="24sp",默认的字体太小,不太好看。

放下一处烦恼,收获一个惊喜;放下一种偏见,收获一种幸福;

【Android】进度条与线程之间的消息处理

相关文章:

你感兴趣的文章:

标签云: