Android应用从后台切回时下载进度Alert Dialog不显示如何解决?
问题根因
- 核心是Activity生命周期与后台线程解绑+Dialog状态管理缺失:
- 当用户切后台时,系统可能因内存不足销毁当前Activity实例,切回时会重建新的Activity实例。你的后台线程持有的是旧Activity的
alertDialog引用,旧实例已经不可见,更新旧Dialog自然不会在新Activity上展示。你在onResume中看到的null是新Activity的alertDialog变量,而后台线程访问的是旧实例的非null变量,这就是你观察到变量状态不一致的原因。 - 就算Activity没有重建,切后台时系统会自动dismiss关联的AlertDialog,但你没有监听dismiss事件将
alertDialog变量置空,后续调用showDialogBox时会走else分支仅更改进度,不会重新调用show()展示弹窗。 - 你之前在
onPause销毁弹窗但没重置alertDialog为null,也会导致同样的问题。
修复步骤
1. 优化Dialog状态管理
修改showDialogBox方法,添加Dialog dismiss监听,每次dismiss后自动重置alertDialog为null,确保后续需要时会重新创建弹窗:
private fun showDialogBox(progress: Int) { runOnUiThread { if (alertDialog == null) { val mDialogView = LayoutInflater.from(this).inflate( R.layout.cdfw_download_status_layout, null ) val mBuilder = AlertDialog.Builder(this) .setView(mDialogView) .setCancelable(false) headingTv = mDialogView.findViewById(R.id.heading) headingSubTv = mDialogView.findViewById(R.id.heading_sub) closeButtonCdfw = mDialogView.findViewById(R.id.close_button) cdfwProgressBarForCdfwDilog = mDialogView.findViewById(R.id.progress_bar) cdfwProgressBarForCdfwDilog.progress = progress alertDialog = mBuilder.show() // 新增dismiss监听,重置变量 alertDialog?.setOnDismissListener { alertDialog = null // 相关控件引用也同步置空,避免内存泄漏 headingTv = null headingSubTv = null closeButtonCdfw = null cdfwProgressBarForCdfwDilog = null } } else { cdfwProgressBarForCdfwDilog?.progress = progress } } }
2. 处理Activity重建场景
不要将下载进度和任务绑定到Activity实例,使用ViewModel存储下载状态与进度,ViewModel生命周期独立于Activity,重建时不会丢失数据:
// 新建DownloadViewModel.kt class DownloadViewModel : ViewModel() { // 下载进度,用StateFlow或者LiveData都可以 val downloadProgress = MutableStateFlow(0) // 标记下载是否进行中 val isDownloading = MutableStateFlow(false) fun startDownload() { viewModelScope.launch(Dispatchers.IO) { isDownloading.value = true // 替换为你的Azure下载逻辑,每次进度更新时修改downloadProgress的值 while (downloadProgress.value < 100) { delay(1000) downloadProgress.value += 10 } isDownloading.value = false } } }
在Activity中观察ViewModel的状态,自动处理弹窗展示与进度更新:
class MainActivity : AppCompatActivity() { private var alertDialog: AlertDialog? = null private lateinit var downloadViewModel: DownloadViewModel override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java] // 观察下载进度 lifecycleScope.launch { repeatOnLifecycle(Lifecycle.State.STARTED) { downloadViewModel.downloadProgress.collect { progress -> if (downloadViewModel.isDownloading.value) { showDialogBox(progress) } else { alertDialog?.dismiss() } } } } // 启动下载的地方调用downloadViewModel.startDownload()即可 } // onPause时如果要销毁弹窗,也要记得置空变量 override fun onPause() { super.onPause() alertDialog?.dismiss() alertDialog = null } }
3. 可选优化
如果下载是长时间后台任务,推荐使用WorkManager实现,避免进程被系统杀死后下载中断,同时可以更方便的监听进度。
内容的提问来源于stack exchange,提问作者Harsh Shah
相关产品推荐
相关产品推荐

