使用安卓视图模型



当我使用ViewModel测试一个小代码时,我注意到一个小的逻辑正确的问题,我想知道你如何解决这个问题。让我们看看这个小类:

public class MyDataViewModel extends ViewModel {
MutableLiveData<List<MyData>> mData = new MutableLiveData<>();
public ContactsViewModel() {}
public void setData(List<MyData> data) {
mData.postValue(data);
}
public LiveData<List<MyData>> getData() {
return mData;
}
}

问题是,如果在注册观察点之前使用setData()更改LiveDataLiveData则在注册观察点后不会触发观察器。尽管这看起来合乎逻辑,但是当您编写异步代码时,它可能会导致问题,并且您不知道在注册观察者之前是否会调用setData()。我想知道当您要注册观察器时,您如何检查数据是否已设置。只需检查是否getData().getValue() != null

另一个问题是数据同步。我是否需要记住LiveData同步(像所有其他正常数据一样(,还是LiveData内部处理它?例如,setData()getData().getValue()可以同时被调用吗?

最后一个问题,似乎观察者会在您设置值时触发LiveData即使它是相同的值(例如,如果您在LoaderonLoadFinished()中使用setData(),则每次重新创建活动时都会调用setData()(。这将导致使用相同的数据调用两次观察者。我想知道防止这种情况的最佳方法是什么。检查ViewModel中的数据是否与我们所拥有的数据相似并且不再设置值?

问题是,如果你在注册 LiveData 观察器之前使用 setData(( 更改 LiveData,你的观察器在注册观察器后不会触发

根据 LiveData 中observe()方法的文档:

/**
* Adds the given observer to the observers list within the lifespan of the given
* owner. The events are dispatched on the main thread. 
* If LiveData already has data set, it will be delivered to the observer.

因此,如果 LiveData 已经设置了数据集,它将被传送给观察者。如果没有,那将是一个错误。


另一个问题是数据同步。我是否需要记住 LiveData 同步(像所有其他普通数据一样(,或者 LiveData 在内部处理它?

当 LiveData 中的数据通过setValue()(仅主线程(或postValue()方法修改时,LiveData 会通知其所有订阅者。

为了使 LiveData 保持最新状态,某些内容必须使用最新数据更新其值,以便将其"广播"给所有订阅者。

例如,当您从 Room 的 DAO 提供LiveData<T> getData();时,Room 会检查T表是否已修改。如果修改了,则更新所有使用 table 进行TLiveData

你几乎永远不需要打电话给getValue()


这将导致使用相同的数据调用两次观察者。我想知道防止这种情况的最佳方法是什么。

如果您正确设置了比较或观察逻辑,这应该无关紧要。

public class TasksViewModel
extends BaseObservable
implements Observer<List<Task>> {    
@Inject
TasksViewModel(...) {
//...
}
private LiveData<Task> liveResults;
public void start() {
liveResults = tasksRepository.getTasks();
liveResults.observeForever(this);
}
public void stop() {
liveResults.removeObserver(this);
}
@Override
public void onChanged(@Nullable List<Task> tasks) {
if(tasks == null) {
return; // loading...
}
items.clear();
items.addAll(tasks); // <-- whether it is same data or not is irrelevant.
notifyPropertyChanged(BR.empty);
}
}

使用Android的ViewModel,您很可能会start()移动到构造函数(使用ViewModelProvider.Factory(,stop()移动到onCleared()

我的情况是有人需要一个只在setData()上调用观察者的LiveData,我写了这个小类。我自己使用它来防止当您决定setData()onLoaderFinished()和活动重新创建时进行多个观察者调用。

public class MutableSemiLiveData<T> extends MutableLiveData<T> {
private volatile boolean mManualSetting = false;
@Override
protected void onInactive() {
super.onInactive();
mManualSetting = false;
}
@Override
public void setValue(T value) {
mManualSetting = true;
super.setValue(value);
}
@Override
public void postValue(T value) {
mManualSetting = true;
super.postValue(value);
}
@Override
public void observe(LifecycleOwner owner, final Observer<T> observer) {
super.observe(owner, new Observer<T>() {
@Override
public void onChanged(@Nullable T t) {
if (mManualSetting) {
observer.onChanged(t);
}
}
});
}
}

请记住,仅当您想通过设置 value 来触发观察者并且它不会在活动重新创建时触发时,才使用此类。

此致敬意

最新更新