是否可以在没有 Factory 的 public 方法中将 id 参数传递给 AndroidViewModel?
Is it possible to pass an id parameter to AndroidViewModel in a public method without Factory?
我正在查看 Android 架构组件示例中的 BasicSample 应用程序。在 ProductViewModel.java 文件中,一些注释显示为:
It's not
actually necessary in this case, as the product ID can be passed in a public method.
根据我对评论的理解,我想知道是否可以在不使用工厂的情况下将 productId 传递给 ProductViewModel,以及如何做到这一点。
我已经实施了转换,我知道我可以使用 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);
}
}
}
productId 来自哪里?
如果它是从存储库(数据库或网络服务)加载的,我猜你不必在 ViewModel 上公开它。
如果它是一个 "dynamic" 值,存储到 SharedPreferences 或从视图中设置,您可以公开一个 Setter 如下
.
public void setProductId(int productId) {
if(mProductId == -1) { // or check mObservableComments
mProductId = productId;
mObservableComments = repository.loadComments(mProductId);
mObservableProduct = repository.loadProduct(mProductId);
}
}
参考样本,当评论说:
the product ID can be passed in a public method
这是指您可以创建 public setter 方法。
由于 productId
用于从您的数据库中获取 LiveData,因此您应该使用 switchMap
,如您所述。这是因为 switchMap
允许您查找和更新 LiveData
指向的内容,而无需重新设置观察者。如果你没有使用 switchMap
,你需要告诉你的 Activity 观察新查找的 LiveData
,并可能停止观察旧的 LiveData
对象. More description of this is included in the docs.
请注意 - 工厂在这里也很有用,因为您正在通过构造函数传入或注入 DataRepository
依赖项。这是将存储库放入 class 的更好方法,因为在测试时很容易模拟存储库。
考虑到这一点,如果您想在工厂中执行此操作,您的代码可能类似于:
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
}
}
我正在查看 Android 架构组件示例中的 BasicSample 应用程序。在 ProductViewModel.java 文件中,一些注释显示为:
It's not actually necessary in this case, as the product ID can be passed in a public method.
根据我对评论的理解,我想知道是否可以在不使用工厂的情况下将 productId 传递给 ProductViewModel,以及如何做到这一点。
我已经实施了转换,我知道我可以使用 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);
}
}
}
productId 来自哪里?
如果它是从存储库(数据库或网络服务)加载的,我猜你不必在 ViewModel 上公开它。
如果它是一个 "dynamic" 值,存储到 SharedPreferences 或从视图中设置,您可以公开一个 Setter 如下
.
public void setProductId(int productId) {
if(mProductId == -1) { // or check mObservableComments
mProductId = productId;
mObservableComments = repository.loadComments(mProductId);
mObservableProduct = repository.loadProduct(mProductId);
}
}
参考样本,当评论说:
the product ID can be passed in a public method
这是指您可以创建 public setter 方法。
由于 productId
用于从您的数据库中获取 LiveData,因此您应该使用 switchMap
,如您所述。这是因为 switchMap
允许您查找和更新 LiveData
指向的内容,而无需重新设置观察者。如果你没有使用 switchMap
,你需要告诉你的 Activity 观察新查找的 LiveData
,并可能停止观察旧的 LiveData
对象. More description of this is included in the docs.
请注意 - 工厂在这里也很有用,因为您正在通过构造函数传入或注入 DataRepository
依赖项。这是将存储库放入 class 的更好方法,因为在测试时很容易模拟存储库。
考虑到这一点,如果您想在工厂中执行此操作,您的代码可能类似于:
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
}
}