LiveData,注册观察者时如何避免第一次回调
LiveData,how to avoid the first callback when register observer
我想在片段中加载任务,在片段的onViewCreated中,我注册了LiveData
观察者,在片段的onResume中,我异步加载任务,当第一次进入片段时,它工作正常,但是当我导航到其他片段然后返回到任务片段,回调 onChanged()
将被调用两次。
我知道如果LiveData已经有数据集,它会被传递给观察者,所以当回到任务片段时,onChanged
会在onViewCreated
中注册观察者时被触发,并且在onResume中,第二次会触发onChanged
,我想知道如何避免这种情况。查了很多,知道有一个EventWrapper
,可以标记第一次触发onChanged时消耗的内容。但我认为这种做法太重了。抱歉我的英语不好...
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle
savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
//...
mainViewModel = ViewModelProviders.of(getActivity()).get(MainViewModel.class);
mainViewModel.increaseTaskList.observe(getViewLifecycleOwner(), new
Observer<List<Task>>() {
@Override
public void onChanged(@Nullable List<Task> tasks) {
Log.d("ZZZ","data changed,IncreaseTaskListAdapter setData");
adapter.setData(tasks);
}
});
}
@Override
public void onResume() {
super.onResume();
mainViewModel.loadIncreasePointTaskList();
}
你可以使用SingleLiveEvent
,只要内容没有改变就不会被触发。
这是 Google 推荐的。
我的简单解决方案是将一个布尔变量声明为 isFisrtCalled = false
,然后第一次在回调中更改它 true
isFirstCalled = false;
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle
savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
//...
mainViewModel = ViewModelProviders.of(getActivity()).get(MainViewModel.class);
mainViewModel.increaseTaskList.observe(getViewLifecycleOwner(), new
Observer<List<Task>>() {
@Override
public void onChanged(@Nullable List<Task> tasks) {
if (!isFirstCalled) {
isFirstCalled = true;
return;
} // this will ensure, you will discard fisrt callback
Log.d("ZZZ","data changed,IncreaseTaskListAdapter setData");
adapter.setData(tasks);
}
});
}
@Override
public void onResume() {
super.onResume();
mainViewModel.loadIncreasePointTaskList();
}
我找到了一个简单的解决方案,加载前检查 livedata 值
@Override
public void onResume() {
super.onResume();
if (mainViewModel.increaseTaskList.getValue()==null) {
Log.d("ZZZ","IncreaseFragment loadTaskAsync");
mainViewModel.loadIncreasePointTaskList();
}
}
我的简单解决方案是扩展您的 MutableliveData class,添加您的自定义观察者方法,这些方法采用可变实时数据参数和一个额外的布尔参数类型,这个布尔值将有助于绕过观察者的第一次回调,我的解决方案将阻止您每次为每个观察者手动处理布尔值,
public class CustomMutableLiveData<T> extends MutableLiveData<T> {
private final AtomicBoolean byPass = new AtomicBoolean(false);
private LifecycleOwner owner;
@NonNull
private Observer<? super T> observer;
public CustomMutableLiveData() {
byPass.set(false);
}
@MainThread
@Override
public void observe(@NonNull LifecycleOwner owner, @NonNull final Observer<? super T> observer) {
super.observe(owner, observer);
}
@MainThread
public void setValue(T value) {
super.setValue(value);
if (this.byPass.get()) {
observe(owner, observer);
this.byPass.set(false);
}
}
public void addObserver(@NonNull LifecycleOwner owner, @NonNull final Observer<? super T> observer) {
addObserver(owner, observer, false);
}
public void addObserver(@NonNull LifecycleOwner owner, @NonNull final Observer<? super T> observer, boolean byPassMode) {
this.owner = owner;
this.observer = observer;
byPass.set(byPassMode);
if (!byPass.get()) {
observe(this.owner, this.observer);
}
}
}
使用自定义观察者方法添加观察者,例如:
mViewModel.name.addObserver(this, name -> {
mBinding.tvName.setGreetingTextText(name);
},true);
mViewModel.name.setValue("Zeeshan 1")
mViewModel.name.addObserver(this, name -> {
mBinding.tvName.setGreetingTextText(name);
},true); // true for byPass call back
mViewModel.name.setValue("Zeeshan 2")
以上示例代码只打印'Zeeshan 2'
希望对您有所帮助。
您现在可以使用 SingleLiveEvent 而不是 MutableData。
所以改变这个:
private val _biometricAuthenticationStatus = MutableLiveData(BiometricAuthenticationStatus.WAITING)
进入这个:
private val _biometricAuthenticationStatus = SingleLiveEvent<BiometricAuthenticationStatus>()
我想在片段中加载任务,在片段的onViewCreated中,我注册了LiveData
观察者,在片段的onResume中,我异步加载任务,当第一次进入片段时,它工作正常,但是当我导航到其他片段然后返回到任务片段,回调 onChanged()
将被调用两次。
我知道如果LiveData已经有数据集,它会被传递给观察者,所以当回到任务片段时,onChanged
会在onViewCreated
中注册观察者时被触发,并且在onResume中,第二次会触发onChanged
,我想知道如何避免这种情况。查了很多,知道有一个EventWrapper
,可以标记第一次触发onChanged时消耗的内容。但我认为这种做法太重了。抱歉我的英语不好...
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle
savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
//...
mainViewModel = ViewModelProviders.of(getActivity()).get(MainViewModel.class);
mainViewModel.increaseTaskList.observe(getViewLifecycleOwner(), new
Observer<List<Task>>() {
@Override
public void onChanged(@Nullable List<Task> tasks) {
Log.d("ZZZ","data changed,IncreaseTaskListAdapter setData");
adapter.setData(tasks);
}
});
}
@Override
public void onResume() {
super.onResume();
mainViewModel.loadIncreasePointTaskList();
}
你可以使用SingleLiveEvent
,只要内容没有改变就不会被触发。
这是 Google 推荐的。
我的简单解决方案是将一个布尔变量声明为 isFisrtCalled = false
,然后第一次在回调中更改它 true
isFirstCalled = false;
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle
savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
//...
mainViewModel = ViewModelProviders.of(getActivity()).get(MainViewModel.class);
mainViewModel.increaseTaskList.observe(getViewLifecycleOwner(), new
Observer<List<Task>>() {
@Override
public void onChanged(@Nullable List<Task> tasks) {
if (!isFirstCalled) {
isFirstCalled = true;
return;
} // this will ensure, you will discard fisrt callback
Log.d("ZZZ","data changed,IncreaseTaskListAdapter setData");
adapter.setData(tasks);
}
});
}
@Override
public void onResume() {
super.onResume();
mainViewModel.loadIncreasePointTaskList();
}
我找到了一个简单的解决方案,加载前检查 livedata 值
@Override
public void onResume() {
super.onResume();
if (mainViewModel.increaseTaskList.getValue()==null) {
Log.d("ZZZ","IncreaseFragment loadTaskAsync");
mainViewModel.loadIncreasePointTaskList();
}
}
我的简单解决方案是扩展您的 MutableliveData class,添加您的自定义观察者方法,这些方法采用可变实时数据参数和一个额外的布尔参数类型,这个布尔值将有助于绕过观察者的第一次回调,我的解决方案将阻止您每次为每个观察者手动处理布尔值,
public class CustomMutableLiveData<T> extends MutableLiveData<T> {
private final AtomicBoolean byPass = new AtomicBoolean(false);
private LifecycleOwner owner;
@NonNull
private Observer<? super T> observer;
public CustomMutableLiveData() {
byPass.set(false);
}
@MainThread
@Override
public void observe(@NonNull LifecycleOwner owner, @NonNull final Observer<? super T> observer) {
super.observe(owner, observer);
}
@MainThread
public void setValue(T value) {
super.setValue(value);
if (this.byPass.get()) {
observe(owner, observer);
this.byPass.set(false);
}
}
public void addObserver(@NonNull LifecycleOwner owner, @NonNull final Observer<? super T> observer) {
addObserver(owner, observer, false);
}
public void addObserver(@NonNull LifecycleOwner owner, @NonNull final Observer<? super T> observer, boolean byPassMode) {
this.owner = owner;
this.observer = observer;
byPass.set(byPassMode);
if (!byPass.get()) {
observe(this.owner, this.observer);
}
}
}
使用自定义观察者方法添加观察者,例如:
mViewModel.name.addObserver(this, name -> {
mBinding.tvName.setGreetingTextText(name);
},true);
mViewModel.name.setValue("Zeeshan 1")
mViewModel.name.addObserver(this, name -> {
mBinding.tvName.setGreetingTextText(name);
},true); // true for byPass call back
mViewModel.name.setValue("Zeeshan 2")
以上示例代码只打印'Zeeshan 2'
希望对您有所帮助。
您现在可以使用 SingleLiveEvent 而不是 MutableData。
所以改变这个:
private val _biometricAuthenticationStatus = MutableLiveData(BiometricAuthenticationStatus.WAITING)
进入这个:
private val _biometricAuthenticationStatus = SingleLiveEvent<BiometricAuthenticationStatus>()