ViewModel 中的 LiveData 未更新
LiveData not updated in ViewModel
在我的 ViewModel class 中,我有一个方法可以从互联网上获取数据并通过 setValue() 将它们设置在 LiveData 上(我使用了这些 docs 中的方法):
public class PageViewModel extends ViewModel {
private MutableLiveData<List<?>> mDataList;
...
private LiveData<List<?> getDataList() {
if (mDataList == null) {
mDataList = new MutableLiveData<>();
}
Handler handler = new Handler(Looper.getMainLooper());
// getData() connects to the internet and fetches the online data
mInternetConnection.getData(new InternetConnection.ConnectionCallback<List<?>>() {
@Override
public void onComplete(Result<List<?>> result) {
if (result instanceof Result.Success) {
mDataList.setValue(((Result.Success<List<?>>) result).data);
} else {
Log.e(LOG_TAG, "ViewModel could not obtain data list");
}
}
}, handler);
return mDataList;
}
但是 mDataList.getValue() 为空。 setValue()
方法在主线程上被调用。
onComplete
肯定会被调用(选中)。
当我在 setValue()
之后的 onComplete
方法中检查 mDataList 的值是否为空时,日志显示它不为空。
为什么是null,修改后的mDataList的值应该如何获取?
我花了几个小时在网上寻找解决方案,但找不到任何有用的东西。本站相关问题也无助于解决问题
编辑:
来自 docs:
在这个例子中,传递给 Repository 的 makeLoginRequest 调用的回调在主线程上执行。这意味着您可以直接从回调中修改 UI 或使用 LiveData.setValue() 与 UI.
通信
所以我遵循了那个,但是这部分:“或使用 LiveData.setValue() 与 UI 通信”不起作用。
Fragment 中设置了观察者,但 LiveData 仍然没有更新 - list
in onChanged
为 null,屏幕保持空白,没有错误。
片段代码:
@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
binding = FragmentMainBinding.inflate(inflater, container, false);
View rootView = binding.getRoot();
binding.listRecyclv.setLayoutManager(new LinearLayoutManager(rootView.getContext()));
mAdapter = createAdapter(rootView.getContext(), pageViewModel.getList().getValue());
binding.listRecyclv.setAdapter(mAdapter);
pageViewModel.getList().observe(getViewLifecycleOwner(), new Observer<List<?>>() {
@Override
public void onChanged(@Nullable List<?> list) {
mAdapter.setList((ArrayList<MyObj>) list);
binding.listRecyclv.setAdapter(mAdapter);
}
}
}
});
Getter 在视图模型中:
public LiveData<List<?>> getList() {
return getDataList();
}
适配器中的代码:
public class AppAdapter extends RecyclerView.Adapter<AppAdapter.AppViewHolder> {
...
public void setList(ArrayList<MyObj> list) {
mAppList = list;
notifyDataSetChanged();
}
提前致谢。
mDataList
为空,因为您为获取数据所做的调用是 asynchronous
。这意味着该函数将在您的 api 调用(及其回调)之前 return。
在此处阅读更多内容 https://www.bmc.com/blogs/asynchronous-programming/
要获取列表,您需要观察数据变化。
所以像这样:
来自activity:
科特林:
viewModel.getDataList().observe(this) { dataList ->
//TODO: Do something with the list
}
Java:
final Observer<String> listObserver = new Observer<List<>>() {
@Override
public void onChanged(@Nullable final List<> newName) {
//TODO: Use the list
}
};
viewModel.getDataList().observe(this, listObserver);
每次列表更改时都会调用观察者内部的逻辑。
我是这样解决的:
- 在 Fragment 的 onCreate 方法中更改了这一行
来自:
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
pageViewModel = new ViewModelProvider(this).get(PageViewModel.class);
到
pageViewModel = new ViewModelProvider(requireActivity()).get(PageViewModel.class);
感谢
- 将 PageViewModel class 中 getDataList() 方法的数据类型从 LiveData 更改为 MutableLiveData(如果没有它,上述步骤将无济于事):
来自:
public class PageViewModel extends ViewModel {
private MutableLiveData<List<?>> mDataList;
...
private LiveData<List<?> getDataList() {
至:
private MutableLiveData<List<?> getDataList() {
现在可以了!现在触发观察器并更新数据。
在我的 ViewModel class 中,我有一个方法可以从互联网上获取数据并通过 setValue() 将它们设置在 LiveData 上(我使用了这些 docs 中的方法):
public class PageViewModel extends ViewModel {
private MutableLiveData<List<?>> mDataList;
...
private LiveData<List<?> getDataList() {
if (mDataList == null) {
mDataList = new MutableLiveData<>();
}
Handler handler = new Handler(Looper.getMainLooper());
// getData() connects to the internet and fetches the online data
mInternetConnection.getData(new InternetConnection.ConnectionCallback<List<?>>() {
@Override
public void onComplete(Result<List<?>> result) {
if (result instanceof Result.Success) {
mDataList.setValue(((Result.Success<List<?>>) result).data);
} else {
Log.e(LOG_TAG, "ViewModel could not obtain data list");
}
}
}, handler);
return mDataList;
}
但是 mDataList.getValue() 为空。 setValue()
方法在主线程上被调用。
onComplete
肯定会被调用(选中)。
当我在 setValue()
之后的 onComplete
方法中检查 mDataList 的值是否为空时,日志显示它不为空。
为什么是null,修改后的mDataList的值应该如何获取?
我花了几个小时在网上寻找解决方案,但找不到任何有用的东西。本站相关问题也无助于解决问题
编辑:
来自 docs: 在这个例子中,传递给 Repository 的 makeLoginRequest 调用的回调在主线程上执行。这意味着您可以直接从回调中修改 UI 或使用 LiveData.setValue() 与 UI.
通信所以我遵循了那个,但是这部分:“或使用 LiveData.setValue() 与 UI 通信”不起作用。
Fragment 中设置了观察者,但 LiveData 仍然没有更新 - list
in onChanged
为 null,屏幕保持空白,没有错误。
片段代码:
@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
binding = FragmentMainBinding.inflate(inflater, container, false);
View rootView = binding.getRoot();
binding.listRecyclv.setLayoutManager(new LinearLayoutManager(rootView.getContext()));
mAdapter = createAdapter(rootView.getContext(), pageViewModel.getList().getValue());
binding.listRecyclv.setAdapter(mAdapter);
pageViewModel.getList().observe(getViewLifecycleOwner(), new Observer<List<?>>() {
@Override
public void onChanged(@Nullable List<?> list) {
mAdapter.setList((ArrayList<MyObj>) list);
binding.listRecyclv.setAdapter(mAdapter);
}
}
}
});
Getter 在视图模型中:
public LiveData<List<?>> getList() {
return getDataList();
}
适配器中的代码:
public class AppAdapter extends RecyclerView.Adapter<AppAdapter.AppViewHolder> {
...
public void setList(ArrayList<MyObj> list) {
mAppList = list;
notifyDataSetChanged();
}
提前致谢。
mDataList
为空,因为您为获取数据所做的调用是 asynchronous
。这意味着该函数将在您的 api 调用(及其回调)之前 return。
在此处阅读更多内容 https://www.bmc.com/blogs/asynchronous-programming/
要获取列表,您需要观察数据变化。
所以像这样:
来自activity:
科特林:
viewModel.getDataList().observe(this) { dataList ->
//TODO: Do something with the list
}
Java:
final Observer<String> listObserver = new Observer<List<>>() {
@Override
public void onChanged(@Nullable final List<> newName) {
//TODO: Use the list
}
};
viewModel.getDataList().observe(this, listObserver);
每次列表更改时都会调用观察者内部的逻辑。
我是这样解决的:
- 在 Fragment 的 onCreate 方法中更改了这一行
来自:
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
pageViewModel = new ViewModelProvider(this).get(PageViewModel.class);
到
pageViewModel = new ViewModelProvider(requireActivity()).get(PageViewModel.class);
感谢
- 将 PageViewModel class 中 getDataList() 方法的数据类型从 LiveData 更改为 MutableLiveData(如果没有它,上述步骤将无济于事):
来自:
public class PageViewModel extends ViewModel {
private MutableLiveData<List<?>> mDataList;
...
private LiveData<List<?> getDataList() {
至:
private MutableLiveData<List<?> getDataList() {
现在可以了!现在触发观察器并更新数据。