2017-06-18 53 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