«

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

时间:2024-3-2 18:27     作者:韩俊     分类: Android


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

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


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

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

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

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <string name="app_name">进度条</string>
    <string name="action_settings">Settings</string>

</resources>
之后,布局也没有什么特别的,思想如下图:


在reslayoutactivity_main.xml中,修改成如下代码即可:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal" >

        <ProgressBar
            android:id="@+id/ProgressBar1"
            style="@android:style/Widget.ProgressBar.Large"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />

        <TextView
             android:id="@+id/TextView1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"/>
    </LinearLayout>

    <ProgressBar
        android: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;

    @Override
    protected 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%时的倒数

            @Override
            public 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() {//这样写,就不弹出什么泄漏的警告了
            @Override
            public 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;
            }
        });
    }

    @Override
    public 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

热门推荐