2017-06-18 84 views
3

我一直在阅读有关中引入Android和我无法弄清楚它是如何工作的新体系结构组件:架构组件:ViewModelProvider如何知道要调用哪个构造函数?

ViewModelProviders.of(Activity).get(Class) 

起初我以为它会调用默认的构造函数,并返回一个视图模型对象,你那么用例如实例化。一个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知道调用提供的构造函数?或者它看到只有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); 
     } 

里面的DefaultFactory类的内部ViewModelProviders.java。但是,这使我更加困惑。当ViewModel对象没有将应用程序作为参数的构造函数时,getConstructor(Application.class)如何工作?

回答

2

在片段存在,检查是否modelClassAndroidViewModel型的(继承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