Android-Download-Manager-Pro库UI不更新:返回后进度条停止刷新
解决Android Download Manager Pro返回再打开后UI进度更新失效问题
我之前也碰到过类似的情况,核心问题出在Activity销毁重建后,旧的UI控件引用已经失效,但后台下载线程还持有旧的引用——导致进度更新到了已经被回收的控件上,新打开的Activity自然看不到变化。下面给你几个可行的解决方案:
方案一:用LiveData观察进度(推荐,符合Android架构规范)
LiveData会自动感知Activity的生命周期,当Activity重建后会自动重新订阅进度变化,完美解决UI引用失效的问题。
- 先定义一个全局的LiveData来托管下载进度:
public class DownloadProgressLiveData { private static final MutableLiveData<Integer> progressLiveData = new MutableLiveData<>(); public static MutableLiveData<Integer> getInstance() { return progressLiveData; } // 下载任务更新进度时调用这个方法 public static void updateProgress(int progress) { progressLiveData.postValue(progress); } }
- 在你的Downloader Activity中订阅这个LiveData:
private TextView p; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_downloader); p = findViewById(R.id.your_progress_text_id); // 订阅进度变化,LiveData自动在主线程回调 DownloadProgressLiveData.getInstance().observe(this, progress -> { p.setText(String.valueOf(progress)); Log.e("****","getTag:---1 "+ p.getTag()); }); }
- 替换原来的
runOnUiThread代码,改成更新LiveData:
// 删掉原来的runOnUiThread块,替换成下面这行 DownloadProgressLiveData.updateProgress(GlobalValue.progressPer);
这样不管你怎么返回再打开Activity,新的Activity都会自动接收最新的进度并更新UI,而且完全不用手动处理线程切换。
方案二:用广播传递进度更新
如果不想引入架构组件,广播也是一个可选方案,需要注意注册和注销的时机避免内存泄漏。
- 定义一个自定义广播接收器:
public class DownloadProgressReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { int progress = intent.getIntExtra("download_progress", 0); // 只在当前Activity处于前台时更新UI if (context instanceof DownloaderActivity) { ((DownloaderActivity) context).updateProgress(progress); } } }
- 在Downloader Activity中注册/注销广播:
private DownloadProgressReceiver progressReceiver; private TextView p; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_downloader); p = findViewById(R.id.your_progress_text_id); // 注册广播 progressReceiver = new DownloadProgressReceiver(); IntentFilter filter = new IntentFilter("com.your.app.action.DOWNLOAD_PROGRESS"); registerReceiver(progressReceiver, filter); } @Override protected void onDestroy() { super.onDestroy(); // 必须注销广播,否则会内存泄漏 unregisterReceiver(progressReceiver); } // 提供给广播调用的UI更新方法 public void updateProgress(int progress) { p.setText(String.valueOf(progress)); Log.e("****","getTag:---1 "+ p.getTag()); }
- 下载进度更新时发送广播:
Intent progressIntent = new Intent("com.your.app.action.DOWNLOAD_PROGRESS"); progressIntent.putExtra("download_progress", GlobalValue.progressPer); // 用ApplicationContext发送,避免持有Activity引用 getApplicationContext().sendBroadcast(progressIntent);
方案三:临时补救:在onResume中手动同步进度
这个方法只能解决Activity重新打开时的一次更新,后续进度变化还是不会自动同步,适合作为前面方案的补充:
@Override protected void onResume() { super.onResume(); // 直接用全局进度更新当前UI p.setText(String.valueOf(GlobalValue.progressPer)); }
总结
优先推荐LiveData方案,它是Android官方为解决生命周期感知和UI更新问题设计的组件,代码更简洁,也能避免很多潜在的内存泄漏问题。
内容的提问来源于stack exchange,提问作者Sumit Kumar




