【问题标题】:Can't reach the recreated activity on Firebase task execution after orientation change方向更改后无法在 Firebase 任务执行中访问重新创建的活动
【发布时间】:2020-03-31 15:58:09
【问题描述】:

我在我的应用程序中使用了一些 Firebase 任务,当它正在执行任务时,我想显示一个加载对话框,该对话框不能通过点击外部或按返回等来取消,并且将在结束时被关闭任务。例如;

FragmentManager fm = getSupportFragmentManager();
LoadingDialog ld = new LoadingDialog();
ld.show(fm, "dialog");

storageReference.getDownloadUrl().addOnSuccessListener(uri -> {
    Fragment dialog = fm.findFragmentByTag("dialog");
    if (dialog != null) {
        LoadingDialog ld = (LoadingDialog) dialog;
        ld.dismiss();
    }
});

当方向状态固定但在处理过程中方向改变fm.findFragmentByTag("dialog");在任务完成后返回null时,它按预期工作。

我的 LoadingDialog 类扩展了 DialogFragment;

@NonNull
@Override
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
    Activity activity = getActivity();
    assert activity != null;
    AlertDialog.Builder builder =
            new AlertDialog.Builder(activity, R.style.LoadingDialog);

    LayoutInflater inflater = activity.getLayoutInflater();
    View view = inflater.inflate(R.layout.dialog_loading, null);
    builder.setView(view);
    setCancelable(false);

    return builder.create();
}


@Override
public void show(FragmentManager manager, String tag) {
    FragmentTransaction ft = manager.beginTransaction();
    ft.add(this, tag);
    ft.commitAllowingStateLoss();
}

为什么我无法使用标签找到我的对话框片段?

编辑:我找到了原因,由于活动重新创建,我无法访问我的对话框片段。我执行任务的旧 Activity 被销毁,它尝试从被销毁的 Activity 访问片段管理器。

感谢@Bö macht Blau,我实现了我的ViewModel 类,并通过使用MutableLiveData 对象将一些信息传递给我观察Firebase 任务执行的活动。 java的一些示例代码;

public class AuthViewModel extends AndroidViewModel {
    public MutableLiveData<LoginInfo> loginInfoLiveData;

    public AuthViewModel(@NonNull Application application) {
        super(application);
        loginInfoLiveData = new MutableLiveData<>();
    }

    public void signIn(String email, String password) {
        FirebaseAuth auth = FirebaseAuth.getInstance();
        auth.signInWithEmailAndPassword(email, password)
                .addOnCompleteListener(task -> {
                    FirebaseUser firebaseUser;
                    firebaseUser = auth.getCurrentUser();
                    LoginInfo loginInfo = new LoginInfo(
                            task.isSuccessful(),
                            firebaseUser != null && firebaseUser.isEmailVerified(),
                            task.getException());
                    loginInfoLiveData.postValue(loginInfo);
                });
    }
}

onCreate方法的活动;

authViewModel = new ViewModelProvider(this,
        ViewModelProvider.AndroidViewModelFactory.getInstance(getApplication()))
        .get(AuthViewModel.class);

authViewModel.loginInfoLiveData.observe(this, loginInfo -> {
    hideLoadingDialog();
    if (loginInfo.isSuccessful()) {
        if (loginInfo.isEmailVerified()) {
            startActivity(new Intent(context, MainActivity.class));
            finish();
        } else {
            auth.signOut();
            toast(R.string.verification_error);
        }
    } else {
        handleException(loginInfo.getException());
    }
});

【问题讨论】:

    标签: android firebase activity-lifecycle


    【解决方案1】:

    您可以将与 Firebase 任务相关的代码移至 ViewModel(甚至移至将 LiveData 对象暴露给 ViewModel 的存储库)。一旦任务成功完成,ViewModel 可以通过调用更新MutableLiveData&lt;Boolean&gt; _loadingSuccess

     _loadingSuccess.postValue(true)
    

    ViewModel 反过来可以暴露你的FragmentActivity 可以观察到的LiveData&lt;Boolean&gt; loadingSuccess = _loadingSuccess

    由于ViewModel 将在配置更改后继续存在,因此FragmentActivity 可以在每次进入前台时重新注册观察者

    Fragment 的代码示例

    override fun onActivityCreated(savedInstanceState: Bundle?) {
        super.onActivityCreated(savedInstanceState)
        viewModel.loadingSuccess.observe(viewLifecycleOwner) { success ->
            run {
                if(success != null){
                    dismissLoadingDialog()
                }
            }
        }
    }
    

    有关 LiveData 和 Viewmodel 的更多信息,请参阅Guide to app architecture

    【讨论】:

    • 我有另一个问题,当我使用postValue 时,它会触发正常的观察方法。但是当配置更改(重新创建活动)时,也会调用观察方法而不调用postValue
    • @RasitAyaz - 是的,这对于 LiveData 来说很正常。在您的情况下,如果值为true,您可以检查加载对话框是否仍在显示,如果是则将其关闭。除此之外,您可以在开始新的加载过程后发布false。不是因为您想采取任何行动,只需确保执行上一个 Firebase 任务时没有true。 LiveData 和一次性消息可能有点棘手。关于这个主题有几篇文章,例如见LiveData with single events
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-11-15
    • 1970-01-01
    • 2023-03-05
    • 1970-01-01
    • 2017-03-07
    • 2012-09-14
    • 1970-01-01
    相关资源
    最近更新 更多