【问题标题】:LiveData not updated in ViewModelViewModel 中的 LiveData 未更新
【发布时间】:2022-01-14 09:41:47
【问题描述】:

在我的 ViewModel 类中,我有一个从 Internet 获取数据并通过 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 肯定会被调用(选中)。

当我在onComplete 方法中检查mDataList 的值是否在setValue() 之后为空时,日志显示它不为空。

为什么是null,修改后的mDataList应该怎么取值?

我花了好几个小时在网上寻找解决方案,但找不到任何有用的东西。本站的相关问题也无助于解决问题。

编辑:

来自docs在此示例中,传递到存储库的 makeLoginRequest 调用的回调在主线程上执行。这意味着您可以直接从回调中修改 UI 或使用 LiveData.setValue() 与 UI 进行通信。

所以我遵循了这一点,但这部分:“或使用 LiveData.setValue() 与 UI 进行通信”不起作用。

在 Fragment 中设置了观察者,但 LiveData 仍未更新 - onChanged 中的 list 为空,屏幕保持空白,没有错误。

片段代码:

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

});

ViewModel 中的 Getter:

public LiveData<List<?>> getList() {
    return getDataList();
}

适配器中的代码:

public class AppAdapter extends RecyclerView.Adapter<AppAdapter.AppViewHolder> {

...

public void setList(ArrayList<MyObj> list) {
    mAppList = list;
    notifyDataSetChanged();
}

提前致谢。

【问题讨论】:

  • 它不应该为空,因为您正在初始化方法中的值。也许您的意思是 LiveData 中的值为空。您可以在观察 LiveData 的位置显示代码吗?如果您确定 setValue 正在被调用但您没有看到更改,请确保变量的实例与您观察到的相同。
  • @juancamilo87 LiveData 本身由于某种原因为空。请看我的编辑,我已经发布了额外的代码
  • 现在我已经修复了 LiveData - 它们不再为空,但它们的值为空

标签: android viewmodel android-livedata mutablelivedata


【解决方案1】:

mDataList 为空,因为您要获取数据的调用是 asynchronous。这意味着该函数将在您的 api 调用(及其回调)之前返回。

在此处阅读更多信息https://www.bmc.com/blogs/asynchronous-programming/

【讨论】:

  • "mDataList 为 null,因为您为获取数据而进行的调用是异步的" - 数据在后台线程中获取,但当它们准备就绪时,将触发回调并且获取的列表为在主线程上设置为 LiveData。感谢您的文章,但它包含我已经知道的一般信息。现在我正在尝试实现这一点,文档只显示了开头,但仍然不清楚如何设置数据
【解决方案2】:

要获取列表,您需要观察数据变化。

所以是这样的:

来自活动:

科特林:

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 中有用于观察的代码,但没有任何反应
  • 设置观察者失败,因为 LiveData 为空
【解决方案3】:

我是这样解决的:

  1. 在 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);

感谢this answer

  1. 将 PageViewModel 类中 getDataList() 方法的数据类型从 LiveData 更改为 MutableLiveData(没有它,上面的步骤没有帮助):

来自:

public class PageViewModel extends ViewModel {  
    private MutableLiveData<List<?>> mDataList;
    ...


    private LiveData<List<?> getDataList() {

到:

    private MutableLiveData<List<?> getDataList() {

现在它可以工作了!观察者现在被触发并且数据被更新。

【讨论】:

    猜你喜欢
    • 2021-11-04
    • 2022-07-27
    • 1970-01-01
    • 1970-01-01
    • 2020-05-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多