我不熟悉LiveData
和ViewModels
的使用,而且我不完全了解如何更新数据。
您不必每次应用数据更改时都更新UI, 观察者可以在每次更改时更新UI。
那句话对我来说毫无意义。我正在使用Sqlite数据库(没有Room),并且正在getItems()
的{{1}}方法中异步获取数据。这是否意味着在数据库中添加或更新数据时,ViewModel
将自动检测到该数据并调用LiveData
?
据Android开发者网站称,它开始观察onChange
中的LiveData
对象。在使用onCreate
之前,我通过查询数据库然后调用LiveData
来刷新onResume
中的数据。
此代码现在在加载notifyDataSetChanged()
时显示数据,但是如果我删除数据库或向数据库中添加新数据,则UI不会反映更改。我只是认为我对Fragment
的工作方式没有基本的了解,在任何地方都找不到很好的解释。
帮我StackOverflow,您是我唯一的希望。
LiveData
答案 0 :(得分:4)
如果birthDate
尚未初始化,则您只能检索一次:
private MutableLiveData<List<String>> items
解决此问题的一种方法是对数据使用public MutableLiveData<List<String>> getItems() {
if (items == null) {
items = new MutableLiveData<>();
getItems();// it's called only once
}
return items;
}
:
ContentObserver
不要忘记注册它来通知数据库中的更改:
...
private final ContentObserver contentObserver = new ContentObserver(new Handler()) {
@Override
public void onChange(boolean selfChange) {
// if there're any changes then perform the request and update the UI
getItems();
}
};
...
我还建议创建一个单独的...
contentResolver.registerContentObserver(<your data content uri>, true, contentObserver);
...
层来负责数据检索,如下所示:
Repository
然后,您的...
private final ContentObserver contentObserver = new ContentObserver(new Handler()) {
@Override
public void onChange(boolean selfChange) {
// if there're any changes then perform the request and update the UI
getItems();
}
};
public LiveData<List<String>> getItems() {
return new MutableLiveData<String>() {
@Override
public void onActive() {
// your async operation here
new Thread({
List<String> items = db.getItems();
postValue(items);
}).start();
contentResolver.registerContentObserver(<your data content uri>, true, contentObserver);
}
@Override
public void onInactive() {
contentResolver.unregisterContentObserver(contentObserver);
}
}
return liveData;
}
...
将需要注入存储库对象,因此将需要ViewModel
来构建ViewModelFactory
的实例,但总体用法类似于此:>
ViewModel
要获取更多信息,请阅读Guide to app architecture
答案 1 :(得分:2)
您的代码似乎正确。您已正确设置了所有内容,并且每次Observer
值更改时,都会在ListFragment
中的LiveData
上收到回调。
但是,使用该代码,LiveData值将永远不会改变,因此您的LiveData的Observer只会被调用一次。您仅在MyViewModel.getItems
中调用onCreate
一次,此方法将完成两件事:返回LiveData并获取项目列表。
第一种方法是将ViewModel getItems
方法分为两种:一种用于获取LiveData,另一种用于刷新实际项目列表。
然后,您可以像以前一样在“片段”中刷新onResume()
中的数据。
它看起来像这样:
public class MyViewModel extends ViewModel {
private final MutableLiveData<List<String>> items = new MutableLiveData<>();
public LiveData<List<String>> getItemsLiveData() {
return items;
}
public void refreshItems() {
List<String> items = GetItems(); //async process
this.items.setValue(items)
}
}
public class ListFragment extends Fragment {
private MyViewModel model;
@Override
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
model = ViewModelProviders.of(getActivity()).get(MyViewModel.class);
final Observer<List<String>> observer = new Observer<List<String>>() {
@Override
public void onChanged(List<String> items) {
//update UI
}
};
model.getItemsLiveData().observe(this, observer);
}
@Override
public void onResume() {
model.refreshItems()
}
}
要更进一步,您将需要更改实际刷新项目的方式。如果要在修改数据库时在ViewModel中收到通知,则还需要在ViewModel与数据库之间的通信中使用Observer模式(带有LiveData的房间,RxJava的Observable或新的协程Flow是开始的好地方)< / p>
这是一个使用RxJava的伪算法示例(但这取决于您选择要使用的Observer库):
public class MyViewModel extends ViewModel {
private final MutableLiveData<List<String>> items = new MutableLiveData<>();
public MyViewModel() {
// In actual code, don't forget to dispose that subscription in ViewModel.onCleared()
myDatabase.getDatabaseObservable()
.subscribe(new Subscriber<List<String>>() {
@Override
public void onCompleted() {
}
@Override
public void onNext(List<String> newItems) {
items.setValue(newItems)
}
@Override
public void onError() {
}
})
}
public LiveData<List<String>> getItemsLiveData() {
return items;
}
}
其中的最后一部分将是在数据库类中创建该Observable(使用像Room一样自动运行的Library或通过创建自己的PublishSubject
)。
答案 2 :(得分:0)
您的代码似乎设置正确。但是您的Observers
的{{1}}方法将被调用一次,因为您的代码中没有任何部分会通知您您对基础数据所做的更改。
我建议您根据是从主线程还是后台调用onChanged()
的{{1}}或MutableLiveData
方法,将数据的变化显式通知观察者线程。或者最好还是使用其数据访问对象(DAO)对象来实现setValue()
数据库。
如果您还不愿意使用postValue()
,那么这里是我做了类似操作的代码段:
ROOM
}
从列表中删除值后,新列表将通过ROOM
方法发送到class HomeViewModel : ViewModel() {
private val _budgetList = MutableLiveData<ArrayList<Budget>>()
val budgetList: LiveData<ArrayList<Budget>> = _budgetList
private val _billList = MutableLiveData<ArrayList<Bill>>()
val billList: LiveData<ArrayList<Bill>> = _billList
init {
_budgetList.value = getBudgetList()
_billList.value = getBills()
}
fun deleteBudget(pos: Int) {
_budgetList.apply {
val newValue = value?.apply { removeAt(pos) } header position
postValue(newValue)
}
}
以进行更新。只需删除该值而不发布它,就不会触发Livedata
的{{1}}的{{1}}方法。我希望这可以帮助某人。