java - 架构组件 : How does the ViewModelProvider know which constructor to call?

标签 java android lifecycle

我一直在阅读有关引入到 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;
    }
}

摘自指南的 fragment :https://developer.android.com/topic/libraries/architecture/guide.html

但是,稍后在指南中有这个 fragment :

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 是如何知道调用提供的构造函数的呢?或者它看到只有 1 个构造函数并调用它?例如,如果有 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);
        }

ViewModelProviders.java 中的 DefaultFactory 类内部。然而,这让我更加困惑。当 ViewModel 对象没有将 Application 作为参数的构造函数时,getConstructor(Application.class) 如何工作?

最佳答案

在代码 fragment 中有一个条件检查 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;
        }
    }
}

这里是 kotlin version . 这是 more read on the subject

关于java - 架构组件 : How does the ViewModelProvider know which constructor to call?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44618769/

相关文章:

Java Socket.readLine() 并不总是读取由 newLine 分隔的整个消息

java - 在 Android 中使用 IExtendedNetworkService 获取 USSD 响应

android - Kotlin 默认构造函数中的两种附加类型?

javascript - Angular 中是否有类似于 Android View Lifecycle 的 onResume 方法?

jsf - 根据每个请求构建 ViewScoped bean……第 99 部分

java - 为什么 HSQLDB 中的数据库约束在 Hibernate 中使用事务时仅在提交期间检查?

java - 如何为特定的url启用spring security

android - 尝试调整可绘制图像的大小?

android - 在 Android Studio 中运行 flutter 项目时出现 Gradle 错误

lifecycle - 我在 _ready() 之后缺少生命周期初始化方法