【问题标题】:How to derive a ViewModel for an object attribute in another ViewModel?如何为另一个 ViewModel 中的对象属性派生 ViewModel?
【发布时间】:2020-02-24 16:41:24
【问题描述】:

我想为另一个 ViewModel 中保存的另一个对象的属性获取一个 ViewModel。

我有这样的关系:一个房子里有很多人。 (人们在 Houses 表中编码的 1:n 关系,而不是使用连接表。)在这种情况下我有一个问题: 现有的 House 将显示在 HouseDetailsActivity 中,其中包含一个 HouseDetailsFragment 和一个 PeopleListFragment。 HouseDetailsActivity 在 onCreate 中获取 HouseViewModel,如下所示:

houseViewModel = ViewModelProviders.of(this, new HouseViewModel.Factory(getApplication(), id)).get(HouseViewModel.class);

HouseViewModel 能够返回 LiveData,因为它从数据库中获取了 HouseEntity。 PeopleListFragment 需要从某个地方获取该房子的人员列表的 LiveData,但不需要了解 PeopleListViewModel 以外的任何视图模型。所以,同样在 HouseDetailsActivity onCreate 中,我得到了一个 PeopleListViewModel,如下所示:

peopleListViewModel = ViewModelProviders.of(this).get(PeopleListViewModel.class);

我希望可以与 PeopleListFragment 共享,如下所示:

peopleViewModel = ViewModelProviders.of(getActivity()).get(PeopleListViewModel.class);

问题是如何将 LiveData 中的人员列表放入 ViewModel。 HouseDetailsActivity (HouseDetailsViewModel) 内的 HouseEntity 中的人员列表不是 LiveData。 (我希望能够通过 PeopleListViewModel 在 PeopleListFragment 中查看 HouseEntity 中的人员列表。)

我看过 MediatorLiveData 的文档,我认为这里不适用,因为最终只有一个 PeopleList 来源。

public class HouseDetailsActivity
{
protected void onCreate(Bundle savedInstanceState)
{
    houseViewModel = ViewModelProviders.of(this, new HouseViewModel.Factory(getApplication(), id)).get(HouseViewModel.class);
    peopleListViewModel = ViewModelProviders.of(this).get(PeopleListViewModel.class);
    /* This can't be done, because the HouseEntity may not yet be loaded to the ViewModel. ie. NullPointerException here
    List<Person> people = m_houseViewModel.getHouse().getPeopleList();
    peopleListViewModel.setPeople(people);
    */
}
}

@Entity(tableName="houses")
public class HouseEntity implements MutableHouse
{
    @PrimaryKey(autoGenerate = true)
    @ColumnInfo(name="hid")
    public int id = 0;

    @ColumnInfo(name="address")
    private String address = null;

    /** This is the encoded people, for multiple in a single database field. */
    @ColumnInfo(name="residents")
    private String residents = null;

    public List<Person> getPeopleList ()
    { return HouseEncoding.decodePeople(getResidents()); }
    ...
}

public class HouseViewModel
{
    private final int houseId;
    private MutableLiveData<HouseEntity> house; // The list of people is inside house here, but not as LiveData

    public LiveData<HouseEntity> getObservableHouse ()
    { return house; }

    HouseViewModel (@NonNull Application application, int houseId)
    {
        super(application);
        this.houseId = houseId;
        this.house = getRepository().getHouseObservable(houseId);
    }

    /**
     * A creator is used to inject the house ID into the ViewModel
     */
    public static class Factory extends ViewModelProvider.NewInstanceFactory
    {
        @NonNull
        private Application application;
        private int houseId;

        public Factory (@NonNull Application application, int houseId)
        {
            this.application = application;
            this.houseId = houseId;
        }

        @Override
        @NonNull
        public <T extends ViewModel> T create (@NonNull Class<T> modelClass)
        {
            //noinspection unchecked
            return (T) new HouseViewModel(application, houseId);
        }
    }
}

public class PeopleListViewModel
{
    private MutableLiveData<List<Person>> people;

    void setPeople (List<Person> people)
    { this.people.setValue(people); }
    ...
}

在 PeopleListFragment 内:

private void observerSetup ()
{
    peopleViewModel.getPeople().observe(this, people -> {
        adapter.setPeople(people); // for RecyclerView
    });
}

【问题讨论】:

    标签: android viewmodel android-livedata android-viewmodel


    【解决方案1】:

    我看到你以不同的方式初始化了这两个视图模型。

    houseViewModel = ViewModelProviders.of(this, new HouseViewModel.Factory(getApplication(), id)).get(HouseViewModel.class);

    peopleListViewModel = ViewModelProviders.of(this).get(PeopleListViewModel.class);

    只是改变:

    houseViewModel = ViewModelProviders.of(this, new HouseViewModel.Factory(getApplication(), id)).get(HouseViewModel.class);

    到这里:

    houseViewModel = ViewModelProviders.of(this, ViewModelProviders.of(this).get(HouseViewModel.class);

    你可以在一个视图中初始化两个viewmdoel。不要害羞。

    【讨论】:

    • 我不能按照你的建议去做。我所做的是以我认为正常的方式将房屋 ID 注入到 HouseViewModel 中
    • 您正在做的事情对于“以正常方式”实现您的目标没有意义。也可以在这里查看stackoverflow.com/a/3259429/4209724
    • 我的意思是为 ViewModel 注入 id 以从存储库/数据库获取可观察对象 (HouseEntity) 的常规方法。我添加了用于执行此操作的构造函数和工厂代码。我在研究我的问题时看到了你提到的帖子。不同之处在于我在 PeopleListViewModel 中想要的集合 (List) 在 HouseViewModel 中不可观察。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-06
    • 1970-01-01
    • 1970-01-01
    • 2013-06-01
    • 1970-01-01
    相关资源
    最近更新 更多