2017-06-18 7 views
3

私は、Androidに導入し、私はこれがどのように動作するかを把握することはできません新しいアーキテクチャコンポーネントについて読んでてきた:アーキテクチャコンポーネント:ViewModelProviderはどのコンストラクタを呼び出すべきかをどのように知っていますか?

ViewModelProviders.of(Activity).get(Class) 

当初、私はそれがデフォルトコンストラクタを呼び出して、あなたのViewModelオブジェクトを返すことを考えました例えばインスタンス化する。

public class UserProfileViewModel extends ViewModel { 
    private String userId; 
    private User user; 

    public void init(String userId) { 
     this.userId = userId; 
    } 
    public User getUser() { 
     return user; 
    } 
} 

あたりなどのinit()メソッドのガイドから取られたスニペット: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つのコンストラクタが存在する場合、何が起こるでしょうか?

私は、コードを掘りしようと、何を私が見つけたことだった:ViewModelProviders.java内部DefaultFactoryクラスの内部

@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); 
     } 

。しかし、これはさらに私を混乱させました。 ViewModelオブジェクトに、アプリケーションを引数として持つコンストラクタがない場合、getConstructor(Application.class)はどのように動作しますか?

答えて

2

スニペットでmodelClassかどうかをチェック条件があるApplicationパラメータをとるコンストラクタ(ViewModelを継承)タイプAndroidViewModelです。これは、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

関連する問題