如何从 livedata 中删除观察者,以便在导航回片段时它不会显示两次
How to remove an observer from livedata so it doesn't show twice when navigating back to the fragment
我有一个片段,当用户成功登录时会显示一个弹出窗口。如果我导航到一个新的片段并返回,会再次显示带有以前用户名的弹出窗口。我使用 SingleLiveEvent 解决了这个问题,但我现在必须重构我的代码以使用 MediatorLiveData,因为我的数据可以来自 2 个源(远程和数据库),并且它与 SingleLiveEvent 不兼容。
我尝试使用事件包装器并删除 onDestroyView() 上的观察者,但到目前为止没有任何效果,当我返回片段时,livedata onChanged 函数不断被调用。这是我的一些片段:
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
binding = FragmentDashboardBinding.inflate(inflater, container, false);
binding.setLifecycleOwner(getActivity());
//Get the attendanceViewModel for registering attendance
attendanceViewModel = ViewModelProviders.of(this).get(AttendanceViewModel.class);
attendanceViewModel.getAttendance().observe(getViewLifecycleOwner(), attendanceAndMember -> {
if (attendanceAndMember != null && attendanceAndMember instanceof AttendanceMemberModel) {
clokedInOutMember = attendanceAndMember.member;
}
showResultClockInOutPopup();
});
return binding.getRoot();
}
private void showResultClockInOutPopup() {
clockInBuilder = new AlertDialog.Builder(getActivity());
View view = getLayoutInflater().inflate(R.layout.status_clock_in_out_popup, null);
TextView responseClockInOut = view.findViewById(R.id.responseClockInOut);
Button dismissButton = view.findViewById(R.id.dismissButton);
//Setup Popup Text
if (clokedInOutMember != null) {
if (StringToBool(clokedInOutMember.is_clocked_in_temp)) {
responseClockInOut.setText("Bienvenue " + clokedInOutMember.name + ", tu es bien enregistré(e).");
} else {
responseClockInOut.setText("Désolé de te voir partir " + clokedInOutMember.name + ", à bientôt!");
}
} else {
responseClockInOut.setText("Oups, il semblerait qu'il y ait une erreur...\n Essaye à nouveau.");
}
[..SETUP ALERTDIALOG...]
//Dismiss popup
dismissButton.setOnClickListener(v -> {
clockInResultDialog.dismiss();
clockInResultPopupShowed = false;
clokedInOutMember = null;
});
clockInResultDialog.show();
clockInResultPopupShowed = true;
}
}
@Override
public void onDestroyView() {
attendanceViewModel.getAttendance().removeObservers(this);
super.onDestroyView();
}
这是我的 ViewModel,我必须使用转换,因为我从片段中获取 userId,传递给 Viewmodel,Viewmodel 将它传递给存储库以供查询(也许有更好的方法?):
public class AttendanceViewModel extends AndroidViewModel {
private AttendanceRepository repository = AttendanceRepository.getInstance();
public LiveData<AttendanceMemberModel> mAttendanceAndMember;
private MutableLiveData<String> mId = new MutableLiveData<>();
private MediatorLiveData<AttendanceMemberModel> mObservableAttendance = new MediatorLiveData<AttendanceMemberModel>();
{
mObservableAttendance.setValue(null);
mAttendanceAndMember = Transformations.switchMap(mId, id -> {
return repository.saveAttendance(id);
});
mObservableAttendance.addSource(mAttendanceAndMember, mObservableAttendance::setValue);
}
public AttendanceViewModel(@NonNull Application application) {
super(application);
}
public LiveData<AttendanceMemberModel> getAttendance() {
return mObservableAttendance;
}
public void setMemberId(String id) {
mId.setValue(id);
}
@Override
protected void onCleared() {
mObservableAttendance.setValue(null);
super.onCleared();
}
}
最好的方法是在 OnViewCreated 方法中绑定视图模型。
@Override
public void onActivityCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
attendanceViewModel = ViewModelProviders.of(this).get(AttendanceViewModel.class);
setUpObservers();
}
private void setUpObservers() {
attendanceViewModel.getAttendance().observe(getViewLifecycleOwner(), attendanceAndMember -> {
if (attendanceAndMember != null && attendanceAndMember instanceof AttendanceMemberModel) {
clokedInOutMember = attendanceAndMember.member;
}
showResultClockInOutPopup();
});
}
如果还是不行,请告诉我。谢谢。
使用其中任何一个,根据您的需要工作和运行。
@Override
public void onPause() {
attendanceViewModel.getAttendance().removeObservers(this);
super.onPause();
}
@Override
public void onStop() {
attendanceViewModel.getAttendance().removeObservers(this);
super.onStop();
}
看看片段的生命周期,它会给你更多的想法。
让我知道这是否有效。
我可以向您推荐两种方法。首先创建一个 boolean
变量是否在 Fragment
中显示对话框,在显示对话框后将其设置为 true
并在显示对话框之前检查是否显示对话框。第二种方法是在显示对话框后将 livedata
值设置为 null 并在显示对话框之前检查观察者值是否为 null。我更喜欢第二种方式。
我有一个片段,当用户成功登录时会显示一个弹出窗口。如果我导航到一个新的片段并返回,会再次显示带有以前用户名的弹出窗口。我使用 SingleLiveEvent 解决了这个问题,但我现在必须重构我的代码以使用 MediatorLiveData,因为我的数据可以来自 2 个源(远程和数据库),并且它与 SingleLiveEvent 不兼容。
我尝试使用事件包装器并删除 onDestroyView() 上的观察者,但到目前为止没有任何效果,当我返回片段时,livedata onChanged 函数不断被调用。这是我的一些片段:
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
binding = FragmentDashboardBinding.inflate(inflater, container, false);
binding.setLifecycleOwner(getActivity());
//Get the attendanceViewModel for registering attendance
attendanceViewModel = ViewModelProviders.of(this).get(AttendanceViewModel.class);
attendanceViewModel.getAttendance().observe(getViewLifecycleOwner(), attendanceAndMember -> {
if (attendanceAndMember != null && attendanceAndMember instanceof AttendanceMemberModel) {
clokedInOutMember = attendanceAndMember.member;
}
showResultClockInOutPopup();
});
return binding.getRoot();
}
private void showResultClockInOutPopup() {
clockInBuilder = new AlertDialog.Builder(getActivity());
View view = getLayoutInflater().inflate(R.layout.status_clock_in_out_popup, null);
TextView responseClockInOut = view.findViewById(R.id.responseClockInOut);
Button dismissButton = view.findViewById(R.id.dismissButton);
//Setup Popup Text
if (clokedInOutMember != null) {
if (StringToBool(clokedInOutMember.is_clocked_in_temp)) {
responseClockInOut.setText("Bienvenue " + clokedInOutMember.name + ", tu es bien enregistré(e).");
} else {
responseClockInOut.setText("Désolé de te voir partir " + clokedInOutMember.name + ", à bientôt!");
}
} else {
responseClockInOut.setText("Oups, il semblerait qu'il y ait une erreur...\n Essaye à nouveau.");
}
[..SETUP ALERTDIALOG...]
//Dismiss popup
dismissButton.setOnClickListener(v -> {
clockInResultDialog.dismiss();
clockInResultPopupShowed = false;
clokedInOutMember = null;
});
clockInResultDialog.show();
clockInResultPopupShowed = true;
}
}
@Override
public void onDestroyView() {
attendanceViewModel.getAttendance().removeObservers(this);
super.onDestroyView();
}
这是我的 ViewModel,我必须使用转换,因为我从片段中获取 userId,传递给 Viewmodel,Viewmodel 将它传递给存储库以供查询(也许有更好的方法?):
public class AttendanceViewModel extends AndroidViewModel {
private AttendanceRepository repository = AttendanceRepository.getInstance();
public LiveData<AttendanceMemberModel> mAttendanceAndMember;
private MutableLiveData<String> mId = new MutableLiveData<>();
private MediatorLiveData<AttendanceMemberModel> mObservableAttendance = new MediatorLiveData<AttendanceMemberModel>();
{
mObservableAttendance.setValue(null);
mAttendanceAndMember = Transformations.switchMap(mId, id -> {
return repository.saveAttendance(id);
});
mObservableAttendance.addSource(mAttendanceAndMember, mObservableAttendance::setValue);
}
public AttendanceViewModel(@NonNull Application application) {
super(application);
}
public LiveData<AttendanceMemberModel> getAttendance() {
return mObservableAttendance;
}
public void setMemberId(String id) {
mId.setValue(id);
}
@Override
protected void onCleared() {
mObservableAttendance.setValue(null);
super.onCleared();
}
}
最好的方法是在 OnViewCreated 方法中绑定视图模型。
@Override
public void onActivityCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
attendanceViewModel = ViewModelProviders.of(this).get(AttendanceViewModel.class);
setUpObservers();
}
private void setUpObservers() {
attendanceViewModel.getAttendance().observe(getViewLifecycleOwner(), attendanceAndMember -> {
if (attendanceAndMember != null && attendanceAndMember instanceof AttendanceMemberModel) {
clokedInOutMember = attendanceAndMember.member;
}
showResultClockInOutPopup();
});
}
如果还是不行,请告诉我。谢谢。
使用其中任何一个,根据您的需要工作和运行。
@Override
public void onPause() {
attendanceViewModel.getAttendance().removeObservers(this);
super.onPause();
}
@Override
public void onStop() {
attendanceViewModel.getAttendance().removeObservers(this);
super.onStop();
}
看看片段的生命周期,它会给你更多的想法。 让我知道这是否有效。
我可以向您推荐两种方法。首先创建一个 boolean
变量是否在 Fragment
中显示对话框,在显示对话框后将其设置为 true
并在显示对话框之前检查是否显示对话框。第二种方法是在显示对话框后将 livedata
值设置为 null 并在显示对话框之前检查观察者值是否为 null。我更喜欢第二种方式。