【问题标题】:MVVM. Set data in ViewModelMVVM。在 ViewModel 中设置数据
【发布时间】:2020-11-22 23:57:52
【问题描述】:

需要将数据放入LiveData中发送给回调。在这种方法中:

    public void setData(List<Data> data) {
    this.currentData.setValue((Data) data);
}

根据文档 setValue 是由 MutableLiveData 调用的,我将 ViewModel 中的 LiveData 替换为 MutableLiveData,但无论如何,当我打开所需的片段时,应用程序崩溃

java.lang.ClassCastException: androidx.room.RoomTrackingLiveData cannot be cast to androidx.lifecycle.MutableLiveData
at avocado.droid.ptitsami.room.DataViewModel.<init>(DataViewModel.java:24)
at avocado.droid.ptitsami.room.DataViewModel$ModelFactory.create(DataViewModel.java:54)
at androidx.lifecycle.ViewModelProvider$FactoryWrapper.create(ViewModelProvider.java:268)
at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:179)
at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:147)
at avocado.droid.ptitsami.fragment.DataFragment.onCreateView(DataFragment.java:57)

如何解决?

视图模型

    public class DataViewModel extends AndroidViewModel {
MutableLiveData<Data> currentData;
DataRepository repository;


public DataViewModel(@NonNull Application application, final int verseId) {
    super(application);
    int verseId1 = verseId;
    repository = new DataRepository(application);
    currentData = (MutableLiveData<Data>) repository.getById(verseId);
}

public LiveData<Data> getById() {
    return currentData;
}

public void setData(List<Data> data) {
    this.currentData.setValue((Data) data);
}


public static class ModelFactory extends ViewModelProvider.NewInstanceFactory {

    @NonNull
    private final Application application;
    private final int dataId;
    private final DataRepository repository;

    public ModelFactory(@NonNull Application application, int id) {
        super();
        this.application = application;
        this.dataId = id;
        repository = new DataRepository(application);
    }

    @NonNull
    @Override
    public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
        if (modelClass == DataViewModel.class) {
            return (T) new DataViewModel(application, dataId);
        }
        return null;
    }
}

片段

   public class DataFragment extends Fragment {
private int dataId;
private static final String KEY_DATA_ID = "KEY_DATA_ID";
public TextView tvTitle;

public DataFragment() {
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    View rootViewRead = inflater.inflate(R.layout.fragment_data, container, false);
    Toolbar toolbar = rootViewRead.findViewById(R.id.toolbar);
    AppCompatActivity activity = (AppCompatActivity) getActivity();
    if (activity != null) {
        activity.setSupportActionBar(toolbar);
    }

    setHasOptionsMenu(true);

    tvTitle = (TextView) rootViewRead.findViewById(R.id.text);

    DataViewModel.ModelFactory factory = new DataViewModel.ModelFactory(
            getActivity().getApplication(), getArguments().getInt(KEY_DATA_ID));

    final DataViewModel model = ViewModelProviders.of(this, factory)
            .get(DataViewModel.class);
    model.getById().observe(this, new Observer<Data>() {
        @Override
        public void onChanged(Data data) {
           model.setData((List<Data>) data);

        }
    });

    return rootViewRead;
}

public static DataFragment forData(int dataId) {
    DataFragment fragment = new DataFragment();
    Bundle args = new Bundle();
    args.putInt(KEY_DATA_ID, dataId);
    fragment.setArguments(args);
    return fragment;
}

存储库

    public class DataRepository {
private DatabaseCopier db;

DataRepository(Application application) {
    db = DatabaseCopier.getInstance(application);
}

LiveData<Data> getById(int id) {
    return db.getDatabase().dataDao().getById(id);
}

【问题讨论】:

  • 你为什么要在 ViewModel 上设置数据?通常在onChange 中,您将数据放入视图或适配器中。 LiveData 用于将数据从您的后端、存储库发送到您的前端、片段。

标签: android android-mvvm


【解决方案1】:

尝试将源添加到 currentData 并将 currentData 从 MutableLivaData 更改为 MediatorLiveData。

 LiveData<Data> data = repository.getById(verseId);
 currentData.addSource(data, observer);

【讨论】:

    【解决方案2】:

    这里有很多奇怪的东西..

    在您的 ViewModel 中,您有 LiveData 的 getter 和 setter:

    public LiveData<Data> getById() {
        return currentData;
    }
    public void setData(List<Data> data) {
        this.currentData.setValue((Data) data);
    }
    

    在您的 LiveData 观察者中,您调用 LiveData 的设置器??

    model.getById().observe(this, new Observer<Data>() {
        @Override
        public void onChanged(Data data) {
           model.setData((List<Data>) data);
    
        }
    });
    

    这没有意义!当调用observe 方法时,模型已经有了这个数据集!所以你不需要打电话给setData。没有主要问题,这将创建一个无限循环!

    现在是您的主要问题:

    androidx.room.RoomTrackingLiveData cannot be cast to androidx.lifecycle.MutableLiveData

    房间数据只能加载到 LiveData。原因是 Room 始终保持一个链接,并在数据库内容发生变化时自动更新它!但因此您不能更改 LiveData 的内容!

    所以请解释原因

    需要将数据放入LiveData中发送给回调。

    你必须改变:

    //MutableLiveData<Data> currentData;
    LiveData<Data> currentData;
    

    model.getById().observe(this, new Observer<Data>() {
        @Override
        public void onChanged(Data data) {
           //model.setData((List<Data>) data); <- this creates an endless loop
           // do here what you want to do with the content of the data
           // if you need to pass it to the viewmodel, do it, but do not call `setValue`
        }
    });
    

    对于特定的用例,MediatorLiveData 可能是合理的,但为此您必须详细解释为什么上面不能为您完成这项工作。

    【讨论】:

      猜你喜欢
      • 2017-06-29
      • 2015-02-12
      • 2013-01-02
      • 1970-01-01
      • 2018-09-10
      • 2020-10-14
      • 1970-01-01
      • 2015-08-21
      • 2011-07-17
      相关资源
      最近更新 更多