我一直在阅读有关Android中引入的新架构组件,我无法弄清楚它是如何工作的:
ViewModelProviders.of(Activity).get(Class)
最初我认为它调用默认构造函数并返回一个ViewModel对象,然后用例如实例化。一个init()方法,按照
public class UserProfileViewModel extends ViewModel {
private String userId;
private User user;
public void init(String userId) {
this.userId = userId;
}
public User getUser() {
return user;
}
}
指南摘录:https://developer.android.com/topic/libraries/architecture/guide.html
然而,稍后在指南中有这个片段:
public class UserProfileViewModel extends ViewModel {
private LiveData<User> user;
private UserRepository userRepo;
@Inject // UserRepository parameter is provided by Dagger 2
public UserProfileViewModel(UserRepository userRepo) {
this.userRepo = userRepo;
}
public void init(String userId) {
if (this.user != null) {
// ViewModel is created per Fragment so
// we know the userId won't change
return;
}
user = userRepo.getUser(userId);
}
那么ViewModelProvider如何知道调用提供的构造函数?或者它看到只有一个构造函数并调用它?例如,如果有2个构造函数会发生什么?
我尝试挖掘代码,我发现的是:
@Override
public <T extends ViewModel> T create(Class<T> modelClass) {
if (AndroidViewModel.class.isAssignableFrom(modelClass)) {
//noinspection TryWithIdenticalCatches
try {
return modelClass.getConstructor(Application.class).newInstance(mApplication);
} catch (NoSuchMethodException e) {
throw new RuntimeException("Cannot create an instance of " + modelClass, e);
} catch (IllegalAccessException e) {
throw new RuntimeException("Cannot create an instance of " + modelClass, e);
} catch (InstantiationException e) {
throw new RuntimeException("Cannot create an instance of " + modelClass, e);
} catch (InvocationTargetException e) {
throw new RuntimeException("Cannot create an instance of " + modelClass, e);
}
}
return super.create(modelClass);
}
DefaultFactory
内的ViewModelProviders.java
课程内部。然而,这让我更加困惑。当getConstructor(Application.class)
对象没有构造函数将Application作为参数时,ViewModel
如何工作?
答案 0 :(得分:4)
在代码段中,有一个条件检查 modelClass 是否为AndroidViewModel
类型(继承ViewModel
),构造函数是否采用Application
参数。这更像是排除Factory
查找匹配特定参数的构造函数的独占案例。
此提供程序在创建时查找构造函数匹配的提供程序参数:
public class ViewModelParameterizedProvider {
private AtomicBoolean set = new AtomicBoolean(false);
private ViewModelStore viewModelStore = null;
static ViewModelParameterizedProvider getProvider() {
return new ViewModelParameterizedProvider();
}
@MainThread
public static ViewModelProvider ofSupportFragment(Fragment fragment, Object... params) {
return getProvider().of(fragment).with(params);
}
@MainThread
public static ViewModelProvider ofActivity(FragmentActivity fragmentActivity, Object... params) {
return getProvider().of(fragmentActivity).with(params);
}
@MainThread
public static ViewModelProvider ofFragment(android.app.Fragment fragment, Object... params) {
return getProvider().of(fragment).with(params);
}
private ViewModelParameterizedProvider of(Fragment fragment) {
checkForPreviousTargetsAndSet();
viewModelStore = ViewModelStores.of(fragment);
return this;
}
private ViewModelParameterizedProvider of(android.app.Fragment fragment) {
FragmentActivity fragAct = (FragmentActivity) fragment.getActivity();
return of(fragAct);
}
private ViewModelParameterizedProvider of(FragmentActivity activity) {
checkForPreviousTargetsAndSet();
viewModelStore = ViewModelStores.of(activity);
return this;
}
private ViewModelProvider with(Object... constructorParams) {
return new ViewModelProvider(viewModelStore, parametrizedFactory(constructorParams));
}
private void checkForPreviousTargetsAndSet() {
if (set.get()) {
throw new IllegalArgumentException("ViewModelStore already has been set. Create new instance.");
}
set.set(true);
}
private ViewModelProvider.Factory parametrizedFactory(Object... constructorParams) {
return new ParametrizedFactory(constructorParams);
}
private final class ParametrizedFactory implements ViewModelProvider.Factory {
private final Object[] mConstructorParams;
ParametrizedFactory(Object... constructorParams) {
mConstructorParams = constructorParams;
}
@Override
public <T extends ViewModel> T create(Class<T> modelClass) {
if (modelClass == null) {
throw new IllegalArgumentException("Target ViewModel class can not be null")
}
Log.w("ParametrizedFactory", "Don't use callbacks or Context parameters in order to avoid leaks!!")
try {
if (mConstructorParams == null || mConstructorParams.length == 0) {
return modelClass.newInstance();
} else {
Class<?>[] classes = new Class<?>[mConstructorParams.length];
for (int i = 0; i < mConstructorParams.length; i++) {
classes[i] = mConstructorParams[i].getClass();
}
return modelClass.getConstructor(classes).newInstance(mConstructorParams);
}
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return null;
}
}
}