Android LiveData,注册观察者时如何避免第一次回调

Android LiveData,注册观察者时如何避免第一次回调,android,fragment,android-livedata,android-viewmodel,Android,Fragment,Android Livedata,Android Viewmodel,我想在片段中加载任务,在片段的onViewCreated中,我注册LiveDataobserver,在片段的onResume中,我异步加载任务,当第一次输入片段时,它工作正常,但是当我导航到其他片段然后返回到任务片段时,回调onChanged()将被调用两次 我知道如果LiveData已经有数据集,它将被传递给观察者,因此当返回到任务片段时,在onViewCreated中注册观察者时将触发onChanged,在onResume中,将第二次触发onChanged,我想知道如何避免这种情况。我搜索了

我想在片段中加载任务,在片段的onViewCreated中,我注册
LiveData
observer,在片段的onResume中,我异步加载任务,当第一次输入片段时,它工作正常,但是当我导航到其他片段然后返回到任务片段时,回调
onChanged()
将被调用两次

我知道如果LiveData已经有数据集,它将被传递给观察者,因此当返回到任务片段时,在
onViewCreated
中注册观察者时将触发
onChanged
,在onResume中,将第二次触发
onChanged
,我想知道如何避免这种情况。我搜索了很多,我知道有一个
EventWrapper
,它可以标记第一次触发onchange时所使用的内容。但我认为这种方法太重了。对不起,我的英语很差

@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();
}
@覆盖
已创建公用void onviewCreate(@NonNull视图,@Nullable Bundle
savedInstanceState){
super.onViewCreated(视图,savedInstanceState);
//...
mainViewModel=ViewModelProviders.of(getActivity()).get(mainViewModel.class);
mainViewModel.increaseTaskList.observe(getViewLifecycleOwner(),新建
观察员(){
@凌驾
公共void onChanged(@Nullable List tasks){
Log.d(“ZZZ”,“数据已更改,增加TaskListAdapter设置数据”);
adapter.setData(任务);
}
});
}
@凌驾
恢复时公开作废(){
super.onResume();
mainViewModel.loadIncreasePointTaskList();
}
您可以使用,只要内容没有更改,它就不会被触发


不过,这是Google推荐的。

我的简单解决方案是将一个布尔变量声明为
isfisrcalled=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();
}
isFirstCalled=false;
@凌驾
已创建公用void onviewCreate(@NonNull视图,@Nullable Bundle
savedInstanceState){
super.onViewCreated(视图,savedInstanceState);
//...
mainViewModel=ViewModelProviders.of(getActivity()).get(mainViewModel.class);
mainViewModel.increaseTaskList.observe(getViewLifecycleOwner(),新建
观察员(){
@凌驾
公共void onChanged(@Nullable List tasks){
如果(!isFirstCalled){
isFirstCalled=true;
返回;
}//这将确保您将放弃第一次回调
Log.d(“ZZZ”,“数据已更改,增加TaskListAdapter设置数据”);
adapter.setData(任务);
}
});
}
@凌驾
恢复时公开作废(){
super.onResume();
mainViewModel.loadIncreasePointTaskList();
}

我找到了一个简单的解决方案,在加载之前检查livedata值

@Override
public void onResume() {
    super.onResume();
    if (mainViewModel.increaseTaskList.getValue()==null) {
        Log.d("ZZZ","IncreaseFragment loadTaskAsync");
        mainViewModel.loadIncreasePointTaskList();
    }
}

我的简单解决方案是扩展您的MutableliveData类,添加您的自定义观察者方法,该方法采用可变的实时数据参数和一个额外的布尔参数类型,此布尔值将有助于绕过观察者的第一次回调,我的解决方案将防止您每次为每个观察者手动处理布尔值

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);
        }
    }

}

以上示例代码仅打印“Zeeshan 2”


我希望这会对你有所帮助。

甚至更好。。使用一个。是的,它也可能是。如果您在
onResume
中加载任务列表,它不是每次返回片段时都会被调用吗?因此,再次触发
onchange
?或者仅当列表为空/空时才加载?

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")