You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Android-Download-Manager-Pro库UI不更新:返回后进度条停止刷新

解决Android Download Manager Pro返回再打开后UI进度更新失效问题

我之前也碰到过类似的情况,核心问题出在Activity销毁重建后,旧的UI控件引用已经失效,但后台下载线程还持有旧的引用——导致进度更新到了已经被回收的控件上,新打开的Activity自然看不到变化。下面给你几个可行的解决方案:

方案一:用LiveData观察进度(推荐,符合Android架构规范)

LiveData会自动感知Activity的生命周期,当Activity重建后会自动重新订阅进度变化,完美解决UI引用失效的问题。

  1. 先定义一个全局的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);
    }
}
  1. 在你的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());
    });
}
  1. 替换原来的runOnUiThread代码,改成更新LiveData:
// 删掉原来的runOnUiThread块,替换成下面这行
DownloadProgressLiveData.updateProgress(GlobalValue.progressPer);

这样不管你怎么返回再打开Activity,新的Activity都会自动接收最新的进度并更新UI,而且完全不用手动处理线程切换。

方案二:用广播传递进度更新

如果不想引入架构组件,广播也是一个可选方案,需要注意注册和注销的时机避免内存泄漏。

  1. 定义一个自定义广播接收器:
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);
        }
    }
}
  1. 在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());
}
  1. 下载进度更新时发送广播:
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

火山引擎 最新活动