我的项目中有一个复杂的屏幕,分成多个片段。我正在尝试为这些类遵循MVVM体系结构,因此哪个片段具有自己的ViewModel
和Contract类。
问题在于,所有ViewModel都需要同一个对象实例(我们将其称为Book
)来进行Room事务。
它是否具有在ViewModel之间共享数据(或LiveData
)的正确方法?我知道Shared ViewModel的概念,但是我不知道是否可以将其应用于这种情况。我还考虑过使用MediatorLiveData
,但也没有很好的方法。
我正在考虑创建一个带有BookObservableProvider
(或LiveData<Book>
)的类(我们叫Rx Subject<Book>
),其中每个ViewModel都注入相同的实例,并且加载/更新总是相同的值。
这是一个好方法吗?
答案 0 :(得分:0)
我个人认为您的方法在这种情况下还不错,但是如果想尝试其他方法,我可以建议您使用RxBus方法。这是一个很棒的article。使用这种方法,您可以简单地在活动中发布数据,其中包含片段,然后在所有片段中监听此特定事件。
类似:
//Activity
RxBus.publish(RxEvent.EventOnBookProvide(bookObject)
和
//Fragment
RxBus.listen(RxEvent.EventOnBookProvide::class.java).subscribe {
useObject(it)
}
如果使用Activity,请不要忘记在onDestroy()中使用Disposable和.dispose();如果使用fragment,请在onDestroyView()中使用它。
答案 1 :(得分:0)
您应该在片段/活动之间共享这些数据(也许使用Intents进行活动),然后由另一个ViewModel处理这些数据
答案 2 :(得分:0)
答案与往常一样,取决于情况。
如果您提出问题的原因是“房间访问”,那么建议您使用一个DataRepository
类来处理所有数据库访问,您只需将该存储库单例传递给每个AndroidViewModel
。
mRepository = ((MainApp) application).getRepository();
在MainApp中:
public DataRepository getRepository() {
return DataRepository.getInstance(getDatabase(), mAppExecutors);
}
和存储库:
public class DataRepository {
private static DataRepository sInstance;
private MediatorLiveData<String> mObservableString;
private DataRepository(final AppDatabase database, final AppExecutors executors) {
mObservableString.addSource(database.myDao().loadString(),
mString -> {
if (database.getDatabaseCreated().getValue() != null) {
mObservableString.postValue(mString);
}
});
}
public static DataRepository getInstance(final AppDatabase database, final AppExecutors executors) {
if (sInstance == null) {
synchronized (DataRepository.class) {
if (sInstance == null) {
sInstance = new DataRepository(database, executors);
}
}
}
return sInstance;
}
// and then your access methods
public LiveData<String> getString() {
return mObservableString;
}
如果要更改引用(源),建议在存储库中使用MediatorLivedata。否则,正常的LiveData可以完成这项工作。
关于ViewModel:
理论上,每个片段都有自己的Viewmodel。而且,如果您通过使用requireActivity()
作为参考来获取它,则可以随处获取每个ViewModel并因此进行共享。
例如:
viewModelA = new ViewModelProvider(requireActivity()).get(ViewModelA.class);
viewModelB = new ViewModelProvider(requireActivity()).get(ViewModelB.class);
您可以在每个Fragment中调用并获取相同的ViewModel实例。如果您觉得DataRepository设置过大,请制作一个具有Room访问权限的ViewModel并从每个Fragment加载它。
答案 3 :(得分:0)
我面临同样的问题。但是,如果您没有为各种片段设置不同的视图模型,或者设计不需要为各种片段使用不同的视图模型,您可以在整个活动(所有其他片段)之间共享一个片段,它们都将共享相同的数据实例。
点击此链接了解更多https://developer.android.com/guide/fragments/communicate
您需要做的是确保所有片段使用相同的上下文启动视图模型(主视图模型)。
static JSONObject addKeyToJson_stringValue(@NonNull JSONObject jsonObject, @NonNull String key, @NonNull String value) {
try {
jsonObject.put(key, value);
} catch (JSONException e) {
e.printStackTrace();
}
return jsonObject;
}
===
@Test
public void test_addKeyToJson_stringValue() throws Exception {
JSONObject jsonObjectSpy = Mockito.spy(new JSONObject());
Mockito.when(jsonObjectSpy.put(anyString(), any())).thenThrow(new JSONException("!!! fake exception"));
Util.addKeyToJson_stringValue(jsonObjectSpy, "key", "value");
assertEquals(0, jsonObjectSpy.length());
}
}
注意这一点
public class FilterFragment extends Fragment {
private ListViewModel viewModel;
@Override
public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
viewModel = new ViewModelProvider(requireActivity()).get(ListViewModel.class);
viewModel.getFilters().observe(getViewLifecycleOwner(), set -> {
// Update the selected filters UI
});
}
viewModel = new ViewModelProvider(requireActivity()).get(ListViewModel.class);
确保所有片段都调用宿主活动的上下文。
你不能以这种方式与活动共享数据,因为当活动被销毁时视图模型实例也被销毁