架构组件:ViewModelProvider如何知道要调用哪个构造函数?

时间:2017-06-18 19:32:53

标签: 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;
    }
}

指南摘录: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如何工作?

1 个答案:

答案 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;
        }
    }
}

这是kotlin version。 这是more read on the subject