Android切换Activity时如何实现进度条后台连续更新不重置
问题定位
你遇到的进度条重置问题由三个直接原因导致:
- 每次页面跳转你都调用了
finish()销毁当前Activity实例,再次切回Activity2时会重新执行onCreate创建全新的页面实例,页面内定义的mProgressStatus变量会被重新初始化为0,进度更新逻辑也会从头启动。 - 你实现的Service没有任何进度计数、状态保存的逻辑,只是启动后弹了个Toast,完全没有承担跨页面保存进度的作用。
- 进度更新逻辑直接绑定在Activity2的生命周期上,页面销毁后计数线程也会被回收,根本做不到跨页面持续累加。另外你在工作线程直接调用
mProgressBar.setProgress()更新UI,本身就存在兼容性崩溃隐患。
最小改动修复方案
不用重构页面结构,按以下步骤修改即可:
- 补全Service的逻辑,把全局进度计数、定时累加的逻辑放到Service中,保证进度值不会随Activity销毁被重置。
- 修正Activity跳转逻辑,不要每次都新建Activity实例+销毁旧实例,通过启动模式和Intent Flag复用已有页面,避免重复走onCreate重置状态。
- Activity2只负责在可见时读取Service中保存的最新进度值更新UI,不要自己持有进度变量、启动计数线程。
修正后的代码
1. 重写Service类
把原来空实现的service.java替换为以下代码,进度值在这里持续累加:
package com.ossus.SC20; import android.app.Service; import android.content.Intent; import android.os.Handler; import android.os.IBinder; import android.os.Looper; public class service extends Service { // 全局进度值,整个app生命周期内持续累加 public static int currentProgress = 0; public static final String ACTION_PROGRESS_UPDATE = "com.ossus.SC20.PROGRESS_UPDATE"; private Handler progressHandler = new Handler(Looper.getMainLooper()); private Runnable progressRunnable; @Override public IBinder onBind(Intent intent) { return null; } @Override public int onStartCommand(Intent intent, int flags, int startId) { // 初始化进度累加任务,已经启动过就不重复创建 if (progressRunnable == null) { progressRunnable = new Runnable() { @Override public void run() { if (currentProgress < 100) { currentProgress++; // 发送广播通知可见的Activity更新进度 Intent updateIntent = new Intent(ACTION_PROGRESS_UPDATE); updateIntent.putExtra("progress", currentProgress); sendBroadcast(updateIntent); } // 到100后停止累加,需要循环的话这里重置为0即可 if (currentProgress < 100) { progressHandler.postDelayed(this, 1000); } } }; progressHandler.postDelayed(progressRunnable, 1000); } return START_STICKY; } @Override public void onDestroy() { super.onDestroy(); progressHandler.removeCallbacks(progressRunnable); } }
2. 修改Activity2(frame_2_activity.java)
去掉内部的计数线程、进度变量,只在页面可见时注册广播接收最新进度,不可见时注销避免内存泄漏:
package com.ossus.SC20; import android.app.Activity; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.os.Bundle; import android.view.View; import android.widget.ImageView; import android.widget.ProgressBar; import android.widget.TextView; import java.text.DateFormat; import java.util.Calendar; import java.util.Timer; import java.util.TimerTask; public class frame_2_activity extends Activity { private ProgressBar mProgressBar; private TextView mLoadingText; private Timer timer; private View _bg__frame_2; private ImageView background_1; private TextView text_view_date; private ImageView logo_2_1; private BroadcastReceiver progressReceiver; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.frame_2_new); startService(new Intent(frame_2_activity.this, service.class)); mProgressBar = (ProgressBar) findViewById(R.id.progressbar); mLoadingText = (TextView) findViewById(R.id.LoadingCompleteTextView); // 注册进度更新广播 progressReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { int progress = intent.getIntExtra("progress", 0); mProgressBar.setProgress(progress); mLoadingText.setText(progress + "% Completed"); } }; registerReceiver(progressReceiver, new IntentFilter(service.ACTION_PROGRESS_UPDATE)); // 进入页面先同步一次当前进度,避免刚进来显示0 mProgressBar.setProgress(service.currentProgress); mLoadingText.setText(service.currentProgress + "% Completed"); // 页面跳转逻辑,添加Flag复用已有Activity实例,不要重复新建 timer = new Timer(); timer.schedule(new TimerTask() { @Override public void run(){ Intent intent = new Intent(frame_2_activity.this, frame_3_activity.class); intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT); startActivity(intent); } }, 10000); Calendar calendar = Calendar.getInstance(); String currentDate = DateFormat.getDateInstance(DateFormat.FULL).format(calendar.getTime()); TextView textViewDate = findViewById(R.id.text_view_date); textViewDate.setText(currentDate); _bg__frame_2 = (View) findViewById(R.id._bg__frame_2); background_1 = (ImageView) findViewById(R.id.background_1); text_view_date = (TextView) findViewById(R.id.text_view_date); logo_2_1 = (ImageView) findViewById(R.id.logo_2_1); } @Override protected void onDestroy() { super.onDestroy(); // 注销广播,取消定时器 if (progressReceiver != null) { unregisterReceiver(progressReceiver); } if (timer != null) { timer.cancel(); } } }
3. 修改Activity1(frame_6_activity.java)和Activity3的跳转逻辑
把原来跳转时的finish()删掉,跳转Intent加上Intent.FLAG_ACTIVITY_REORDER_TO_FRONT标记,复用栈里已有的Activity实例,不要每次新建销毁。
比如Activity1里的跳转代码改成:
timer = new Timer(); timer.schedule(new TimerTask() { @Override public void run(){ Intent intent = new Intent(frame_6_activity.this, frame_2_activity.class); intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT); startActivity(intent); } }, 10000);
Activity3里跳转到Activity1的逻辑也做同样修改,去掉finish(),加上Flag即可。
4. 清单文件配置调整
给三个Activity都加上android:launchMode="singleTop"配置,避免重复创建实例,在每个<activity>标签内补充这行属性即可。
注意:严禁在工作线程直接操作View控件,所有UI更新必须切到主线程执行,否则在Android 9及以上版本会直接抛出CalledFromWrongThreadException崩溃。
如果需要进度条走完100%后自动重置循环,只需要在Service的进度累加逻辑里,判断到
currentProgress >=100的时候把值重置为0即可。
内容的提问来源于stack exchange,提问作者Krishna Puvvala
相关产品推荐
相关产品推荐

