方向更改后无法在 Firebase 任务执行时到达重新创建的 activity
Can't reach the recreated activity on Firebase task execution after orientation change
我在我的应用程序中使用了一些 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");
returns 任务完成后为空。
我的 LoadingDialog class 扩展了 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 被销毁,它试图从被销毁的 activity.
访问片段管理器
感谢@Bö macht Blau,我实现了我的 ViewModel
class 并通过使用 MutableLiveData
对象将一些信息传递到我的 activity 我观察 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);
});
}
}
在 activity 的 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());
}
});
您可以将与 Firebase 任务相关的代码移至 ViewModel
(甚至移至将 LiveData
对象公开给 ViewModel
的存储库)。任务成功完成后,ViewModel
可以通过调用
更新 MutableLiveData<Boolean> _loadingSuccess
_loadingSuccess.postValue(true)
ViewModel
反过来可以暴露一个 LiveData<Boolean> loadingSuccess = _loadingSuccess
,您的 Fragment
或 Activity
可以观察到。
由于 ViewModel
将在配置更改后继续存在,因此 Fragment
或 Activity
可以在每次到达前台时重新注册观察者
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
我在我的应用程序中使用了一些 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");
returns 任务完成后为空。
我的 LoadingDialog class 扩展了 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 被销毁,它试图从被销毁的 activity.
访问片段管理器感谢@Bö macht Blau,我实现了我的 ViewModel
class 并通过使用 MutableLiveData
对象将一些信息传递到我的 activity 我观察 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);
});
}
}
在 activity 的 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());
}
});
您可以将与 Firebase 任务相关的代码移至 ViewModel
(甚至移至将 LiveData
对象公开给 ViewModel
的存储库)。任务成功完成后,ViewModel
可以通过调用
MutableLiveData<Boolean> _loadingSuccess
_loadingSuccess.postValue(true)
ViewModel
反过来可以暴露一个 LiveData<Boolean> loadingSuccess = _loadingSuccess
,您的 Fragment
或 Activity
可以观察到。
由于 ViewModel
将在配置更改后继续存在,因此 Fragment
或 Activity
可以在每次到达前台时重新注册观察者
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