You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android屏幕旋转时LiveData(ViewModel)与ProgressDialog异常处理求助

解决屏幕旋转时ProgressDialog无法消失的问题

首先咱们拆解下你遇到的核心问题:

当屏幕旋转时,BillDisplayFragment会被销毁并重建。这时候你重新注册了LiveData的观察者,但LiveData默认不会在观察者重新注册时主动发送已有的旧数据(除非数据有更新),所以onChanged方法不会触发,导致ProgressDialog一直显示无法消失。另外还要检查你的ViewModel是否每次都返回新的LiveData实例——如果是的话,重建后的Fragment拿到的LiveData根本没有之前的数据,自然也不会触发回调。

下面给你几个具体的解决方案,一步步来:

1. 确保ViewModel中的LiveData是持久化的单例实例

首先,ViewModel里的getBillGetResponseDisplayById方法不应该每次调用都创建新的MutableLiveData。正确的做法是把LiveData作为ViewModel的成员变量,只有第一次调用时才初始化:

public class BillDisplayViewModel extends ViewModel {
    private MutableLiveData<BillGetResponse> displayByIdLiveData;

    public MutableLiveData<BillGetResponse> getBillGetResponseDisplayById(TxnRequest txnRequest) {
        if (displayByIdLiveData == null) {
            displayByIdLiveData = new MutableLiveData<>();
            // 在这里发起数据请求,比如调用Repository获取账单数据
            fetchBillData(txnRequest);
        }
        // 如果txnRequest可能变化,这里需要判断是否需要重新发起请求
        return displayByIdLiveData;
    }

    private void fetchBillData(TxnRequest txnRequest) {
        // 你的网络请求逻辑,请求完成后调用displayByIdLiveData.setValue(...)
    }
}

这样,屏幕旋转时ViewModel不会被销毁,LiveData实例保持不变,里面的已加载数据也会保留。

2. 观察LiveData前先检查已有数据

在Fragment重建后,注册观察者之前,先检查LiveData当前是否已经有数据。如果有,直接执行关闭ProgressDialog和更新UI的逻辑:

final ProgressDialog pd = new ProgressDialog(getContext());
pd.setMessage(getString(R.string.updating));
pd.show();

MutableLiveData<BillGetResponse> displayByIdLiveData = viewModelForBillDisplay.getBillGetResponseDisplayById(txnRequest);

// 先检查LiveData是否已有数据
BillGetResponse existingData = displayByIdLiveData.getValue();
if (existingData != null) {
    if (btnRecordDisableEnabled != null) btnRecordDisableEnabled.enable();
    pd.dismiss();
}

if (display_by_id) {
    displayByIdLiveData.observe(BillDisplayFragment.this, new Observer<BillGetResponse>() {
        @Override
        public void onChanged(@Nullable BillGetResponse billGetResponse) {
            if (btnRecordDisableEnabled != null) btnRecordDisableEnabled.enable();
            pd.dismiss();
        }
    });
}

这样一来,如果数据已经加载完成(比如旋转前就拿到了数据),重建后的Fragment会直接关闭ProgressDialog,不需要等待onChanged触发。

3. 处理ProgressDialog的生命周期,避免内存泄漏

屏幕旋转时,原来的Fragment实例会被销毁,如果ProgressDialog持有旧的Context引用,容易造成内存泄漏。建议在Fragment的onDestroyView方法中手动关闭ProgressDialog:

@Override
public void onDestroyView() {
    super.onDestroyView();
    if (pd != null && pd.isShowing()) {
        pd.dismiss();
        pd = null;
    }
}

这样可以保证Fragment销毁时,ProgressDialog也会被正确关闭,不会残留。

额外提示:考虑使用DialogFragment替代ProgressDialog

ProgressDialog已经被标记为废弃(deprecated),官方推荐使用DialogFragment来实现弹窗逻辑。DialogFragment会自动处理屏幕旋转等生命周期变化,不需要你手动管理,能避免很多类似的问题。

内容的提问来源于stack exchange,提问作者Santanu Sur

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 08:06:23