是否可以在没有Factory的公共方法中将id参数传递给AndroidViewModel?

时间:2018-01-10 04:01:14

标签: android android-architecture-components

我正在查看Android架构组件样本中的BasicSample应用程序。在ProductViewModel.java文件中,读取了一些注释:

  

不是             在这种情况下实际上是必要的,因为产品ID可以在公共方法中传递。

根据我对评论的理解,我想知道是否可以在不使用工厂的情况下将productId传递给ProductViewModel,以及如何做到这一点。

我已经实现了Transformation,我知道我可以使用switchMap传递productId。但我正在寻找一种方法来用一个id来初始化模型。

public class ProductViewModel extends AndroidViewModel {

    private final LiveData<ProductEntity> mObservableProduct;

    public ObservableField<ProductEntity> product = new ObservableField<>();

    private final int mProductId;

    private final LiveData<List<CommentEntity>> mObservableComments;

    public ProductViewModel(@NonNull Application application, DataRepository repository,
            final int productId) {
        super(application);
        mProductId = productId;

        mObservableComments = repository.loadComments(mProductId);
        mObservableProduct = repository.loadProduct(mProductId);
    }

...

   /**
     * A creator is used to inject the product ID into the ViewModel
     * <p>
     * This creator is to showcase how to inject dependencies into ViewModels. It's not
     * actually necessary in this case, as the product ID can be passed in a public method.
     */
    public static class Factory extends ViewModelProvider.NewInstanceFactory {

        @NonNull
        private final Application mApplication;

        private final int mProductId;

        private final DataRepository mRepository;

        public Factory(@NonNull Application application, int productId) {
            mApplication = application;
            mProductId = productId;
            mRepository = ((BasicApp) application).getRepository();
        }

        @Override
        public <T extends ViewModel> T create(Class<T> modelClass) {
            //noinspection unchecked
            return (T) new ProductViewModel(mApplication, mRepository, mProductId);
        }
    }
}

2 个答案:

答案 0 :(得分:2)

参考样本时,评论说:

  

产品ID可以通过公共方法传递

这指的是您可以创建公共setter方法。

由于productId用于从您的数据库获取LiveData,因此您应该使用switchMap,如您所述。这是因为switchMap允许您查找和更新LiveData指向的内容,而无需重新设置观察者。如果您没有使用switchMap,则需要告诉您的活动观察新查找的LiveData,并可能停止观察旧的LiveData对象。 More description of this is included in the docs

还有一点需要注意 - 工厂在这里也很有用,因为你通过构造函数传入或者注入 DataRepository依赖项。这是将存储库放入类中的一种更好的方法,因为在测试时可以很容易地模拟存储库。

考虑到这一点,如果你想这样做是工厂,你的代码可能看起来像:

public class ProductViewModel extends AndroidViewModel {

    private final LiveData<ProductEntity> mProduct;
    private final LiveData<List<CommentEntity>> mComments;
    private final MutableLiveData<Integer> mProductId = new MutableLiveData<>();


    public ProductViewModel(@NonNull Application application) {
        super(application);

        // Have some way to get your repository, this is not great for testing...
        Repository repository = ((BasicApp) application).getRepository();

            mProduct = Transformations.switchMap(mProductId, id -> {
            return repository.loadProduct(id);
        }

            mComments = Transformations.switchMap(mComments, id -> {
            return repository.loadComments(id);
        }
    }

    public void setProductId(int productId) {
       mProductId.setValue(productId); // This will trigger both of those switchMap statements
    }

}

答案 1 :(得分:0)

productId 来自哪里?

  • 如果它是从存储库(数据库或Web服务)加载的,那么您不必在ViewModel上公开它。

  • 如果它是一个“动态”值,存储在SharedPreferences中或从视图中设置,您可以公开一个Setter,如下所示

 public void setProductId(int productId) {
       if(mProductId == -1) { // or check mObservableComments 
              mProductId = productId;
              mObservableComments = repository.loadComments(mProductId);
              mObservableProduct = repository.loadProduct(mProductId);
       }
}