ViewModelソース分析
12089 ワード
ViewModelって何?ViewModelはActivityとFragmentのデータを管理するクラスで、ActivityとFragmentとは独立しており、ActivityとFragmentが画面回転などで破棄されても、ActivityとFragmentが再作成されれば元のViewModelと再バインドできます.まず、ViewModelの取得方法を確認します.
ViewModelProvider.get(key,class)メソッドは、取得するviewmodelインスタンスがすでにViewModelStroeに存在するかどうかを先に問い合せる方法であり、インスタンスがすでにViewModelStoreに存在する場合は、前のインスタンスを返し、そうでない場合はViewModelProvider.FactoryはviewModelインスタンスを作成し、viewModelに保存します.次にこのタイプのviewModelを取得するときは、同じViewModelStroeであれば、キャッシュされたviewModelを返すことができます.では、Activityが再作成されてもviewModelを取得するか、それとも前のView Modelを取得するかをどのように保証しますか?ViewModelStroe内部はMapのみでViewModelのキャッシュを管理しているため、Activity破棄再構築後、ViewModelStroeが同じであることを保証するだけで、元のViewModelが入手できることを保証する.ViewModelStroeはどこから来ましたか?引き続き見てof()の実装:
ofメソッドの実装により、ViewModelStoreは、ViewModelStoreOwnerを実装したActivityとFragmentによって提供され、以下の2つの部分に分けてActivityとFragmentの実装を表示する.
Activityはすべて再作成されましたが、activityはどのようにしてView ModelStoreを保証しますか?それとも元のものですか?次はActivity.getViewModelStroeの実装:
ActivityはNonConfiguration InstancesによってViewModelStoreの管理を実現し、最後のNonConfiguration Instancesインスタンスを取得した後、NonConfiguration Instancesを表示する.自分に価値を与えるviewModelStoreとはActivityが再構築前のViewModelStoreを破棄することです
ここまで来るとまたNonConfigurationInstancesが見えますが、ここはちょっと迷います.getViewModelStoreのNonConfigurationInstancesはComponentActivityです.NonConfigurationInstances,getLastNonConfigurationInstanceにあるのはActivity.NonConfigurationInstances,ComponentActivity.NonConfigurationInstancesはViewModelStoreを管理し、Activity.NonConfigurationInstancesはComponentActivityを管理する.NonConfigurationInstances.次にgetLastNonConfigurationInstance()を見続けますが、このmLastNonConfigurationInstancesはどこで作成されたのでしょうか?それは...attach()ではパラメータとして外部から伝達される.activity.attch()はActivity Thread.performLaunchActivity()で呼び出されます.
追跡を続ける牙列缺损LastNonConfigurationInstancesはActivity ClientRecordに由来する.A l e s t NonConfigurationInstancesでは、Activity ClientRecord.LastNonConfigurationInstancesはいつ付与されたのですか?答えはactivityが破壊された時、私たちはActivity Threadを見続けた.performDestroyActivity():
...PerformDestroyActivity()でActivity.retainNonConfigurationInstances()戻り値はActivity ClientRecordに割り当てられます.义齿retainNonConfigurationInstances():
retainNonConfigurationInstances()では、Activityを返します.NonConfigurationInstanceの例で、よく知られているコードが表示されます.
onRetainNonConfigurationInstance()は、ViewModelStroeを持つComponentActivityを作成しました.NonConfigurationInstanceオブジェクトは、Activity破棄再作成を追跡し、ViewModelは変わらないプロセスを維持します.まとめ:1、Activity破棄時にActivity.retainNonConfigurationInstances()Activityを作成する.NonConfigurationInstaceオブジェクトはActivity ClientRcordに渡されて保存され、Activity.NoConfigurationInstance.义齿NonConfigurationInstanceオブジェクト、ComponentActivity.NonConfigurationInstanceは、ViewModelStore 2、Activity作成後、Activityを持つ.attch()では、Activity ClientRcordが持つActivity.NonConfiguration InstaceオブジェクトはActivityに割り当てられます.mLastNonConfigurationInstances 3は、ViewModelProvidersを呼び出す.of()の場合、ComponentActivityが呼び出されます.getViewModelStore()は、getViewModelStore()で2のmLastNonConfigurationInstancesでComponentActivityを取得します.NonConfigurationInstanceオブジェクト、およびComponentActivity.NonConfigurationInstanceが所有するViewModelStoreが返されます.これによりActivity破棄の再作成が保証され、ViewModelStoreはその破棄前のViewModelStoreなので、
Fragment.getViewModelStore()は、次のように実装されます.
fragment自身はView Modelを直接管理せず、エージェントFragmentManagement.を通じてgetView Model()はView Modelに戻り、次にFragmentMangerを見ます.getViewModelの実装:FragmentManagerImpl.getViewModel()
FragmentManagerImplはまたmNonConfigを通じてView ModelStoreを管理し、mNonConfigがいつ作成されたかを見てみましょう.
FragmentがサブFragmentであるか、ActivityがViewModelStoreOwnerを実現しているかによって、1、FragmentルートFragmentでActivityがViewModelStoreOwnerインタフェースを実現する場合、Activity.getViewModelStoreはviewModelStoreを取得します.上記の分析から、このviewModelStoreは再作成前のviewModelStoreを破棄していることがわかります.mNonConfigはViewModelなので、viewModelStoreで取得したmNonConfigも再構築前のmNonCofigを破棄しています.2、fragmentが子fragmentの場合、mNonConfigは親FragmentのmNonConfigから取得し、activityがViewModelStoreOwnerを実現した場合、1に戻り、mNonCofigは破棄前のmNonCofigである.ActivityがViewModelStoreOwnerを実装していない場合は、3に戻ります.3.ActivityがViewModelStoreOwnerを実装場合、新しいmNonConfigを新規作成する.mNonConfigは破棄前のmNonConfigであるため、mNonConfigによって管理されるViewModelStoreも当然破棄前のViewModelStoreである.このことからfragmentのviewModeStoreを保証する際に破棄する前のViewModelStoreはActivityの実現に依存していることがわかる.
val viewModel = ViewModelProviders.of(target, factory).get(PlanViewModel::class.java)
ViewModelProviders.of()メソッドは、ViewModelProviderのインスタンスを取得し、get()メソッドによりViewModel,ViewModelProviderを取得する.get()は以下のように実現される.public T get(@NonNull String key, @NonNull Class modelClass) {
ViewModel viewModel = mViewModelStore.get(key);
if (modelClass.isInstance(viewModel)) {
//noinspection unchecked
return (T) viewModel;
} else {
//noinspection StatementWithEmptyBody
if (viewModel != null) {
// TODO: log a warning.
}
}
viewModel = mFactory.create(modelClass);
mViewModelStore.put(key, viewModel);
//noinspection unchecked
return (T) viewModel;
}
ViewModelProvider.get(key,class)メソッドは、取得するviewmodelインスタンスがすでにViewModelStroeに存在するかどうかを先に問い合せる方法であり、インスタンスがすでにViewModelStoreに存在する場合は、前のインスタンスを返し、そうでない場合はViewModelProvider.FactoryはviewModelインスタンスを作成し、viewModelに保存します.次にこのタイプのviewModelを取得するときは、同じViewModelStroeであれば、キャッシュされたviewModelを返すことができます.では、Activityが再作成されてもviewModelを取得するか、それとも前のView Modelを取得するかをどのように保証しますか?ViewModelStroe内部はMapのみでViewModelのキャッシュを管理しているため、Activity破棄再構築後、ViewModelStroeが同じであることを保証するだけで、元のViewModelが入手できることを保証する.ViewModelStroeはどこから来ましたか?引き続き見てof()の実装:
public static ViewModelProvider of(@NonNull Fragment fragment, @Nullable Factory factory) {
Application application = checkApplication(checkActivity(fragment));
if (factory == null) {
factory = ViewModelProvider.AndroidViewModelFactory.getInstance(application);
}
return new ViewModelProvider(fragment.getViewModelStore(), factory);
}
public static ViewModelProvider of(@NonNull FragmentActivity activity,
@Nullable Factory factory) {
Application application = checkApplication(activity);
if (factory == null) {
factory = ViewModelProvider.AndroidViewModelFactory.getInstance(application);
}
return new ViewModelProvider(activity.getViewModelStore(), factory);
}
ofメソッドの実装により、ViewModelStoreは、ViewModelStoreOwnerを実装したActivityとFragmentによって提供され、以下の2つの部分に分けてActivityとFragmentの実装を表示する.
ActivityがViewModelStoreをどのように管理するか
Activityはすべて再作成されましたが、activityはどのようにしてView ModelStoreを保証しますか?それとも元のものですか?次はActivity.getViewModelStroeの実装:
ComponentActivity.java
public ViewModelStore getViewModelStore() {
if (getApplication() == null) {
throw new IllegalStateException("Your activity is not yet attached to the "
+ "Application instance. You can't request ViewModel before onCreate call.");
}
if (mViewModelStore == null) {
NonConfigurationInstances nc =
(NonConfigurationInstances) getLastNonConfigurationInstance();
if (nc != null) {
// Restore the ViewModelStore from NonConfigurationInstances
mViewModelStore = nc.viewModelStore;
}
if (mViewModelStore == null) {
mViewModelStore = new ViewModelStore();
}
}
return mViewModelStore;
}
ActivityはNonConfiguration InstancesによってViewModelStoreの管理を実現し、最後のNonConfiguration Instancesインスタンスを取得した後、NonConfiguration Instancesを表示する.自分に価値を与えるviewModelStoreとはActivityが再構築前のViewModelStoreを破棄することです
public Object getLastNonConfigurationInstance() {
return mLastNonConfigurationInstances != null
? mLastNonConfigurationInstances.activity : null;
}
ここまで来るとまたNonConfigurationInstancesが見えますが、ここはちょっと迷います.getViewModelStoreのNonConfigurationInstancesはComponentActivityです.NonConfigurationInstances,getLastNonConfigurationInstanceにあるのはActivity.NonConfigurationInstances,ComponentActivity.NonConfigurationInstancesはViewModelStoreを管理し、Activity.NonConfigurationInstancesはComponentActivityを管理する.NonConfigurationInstances.次にgetLastNonConfigurationInstance()を見続けますが、このmLastNonConfigurationInstancesはどこで作成されたのでしょうか?それは...attach()ではパラメータとして外部から伝達される.activity.attch()はActivity Thread.performLaunchActivity()で呼び出されます.
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
...
activity.attach(appContext, this, getInstrumentation(), r.token,
r.ident, app, r.intent, r.activityInfo, title, r.parent,
r.embeddedID, r.lastNonConfigurationInstances, config,
r.referrer, r.voiceInteractor, window, r.configCallback);
...
return activity;
}
追跡を続ける牙列缺损LastNonConfigurationInstancesはActivity ClientRecordに由来する.A l e s t NonConfigurationInstancesでは、Activity ClientRecord.LastNonConfigurationInstancesはいつ付与されたのですか?答えはactivityが破壊された時、私たちはActivity Threadを見続けた.performDestroyActivity():
ActivityThread.performDestroyActivity() {
if (getNonConfigInstance) {
try {
r.lastNonConfigurationInstances = r.activity.retainNonConfigurationInstances();
} catch (Exception e) {
if (!mInstrumentation.onException(r.activity, e)) {
throw new RuntimeException(
"Unable to retain activity "
+ r.intent.getComponent().toShortString()
+ ": " + e.toString(), e);
}
}
}
}
...PerformDestroyActivity()でActivity.retainNonConfigurationInstances()戻り値はActivity ClientRecordに割り当てられます.义齿retainNonConfigurationInstances():
NonConfigurationInstances retainNonConfigurationInstances() {
Object activity = onRetainNonConfigurationInstance();
HashMap children = onRetainNonConfigurationChildInstances();
// Fragment mNonConfig , Fragment
FragmentManagerNonConfig fragments = mFragments.retainNestedNonConfig();
// We're already stopped but we've been asked to retain.
// Our fragments are taken care of but we need to mark the loaders for retention.
// In order to do this correctly we need to restart the loaders first before
// handing them off to the next activity.
mFragments.doLoaderStart();
mFragments.doLoaderStop(true);
ArrayMap loaders = mFragments.retainLoaderNonConfig();
if (activity == null && children == null && fragments == null && loaders == null
&& mVoiceInteractor == null) {
return null;
}
NonConfigurationInstances nci = new NonConfigurationInstances();
nci.activity = activity;
nci.children = children;
nci.fragments = fragments;
nci.loaders = loaders;
if (mVoiceInteractor != null) {
mVoiceInteractor.retainInstance();
nci.voiceInteractor = mVoiceInteractor;
}
return nci;
}
retainNonConfigurationInstances()では、Activityを返します.NonConfigurationInstanceの例で、よく知られているコードが表示されます.
Object activity = onRetainNonConfigurationInstance();
nci.activity = activity;
get LastNonConfigurationInstance()メソッドに戻ると、return mLastNonConfigurationInstances != null ? mLastNonConfigurationInstances.activity : null;
はonRetainNonConfigurationInstance()がViewModelStoreを管理するComponentActivityを返すことを知っています.NonConfigurationInstanceオブジェクト、次にその実装を見ます.@Override
@Nullable
public final Object onRetainNonConfigurationInstance() {
Object custom = onRetainCustomNonConfigurationInstance();
ViewModelStore viewModelStore = mViewModelStore;
if (viewModelStore == null) {
// No one called getViewModelStore(), so see if there was an existing
// ViewModelStore from our last NonConfigurationInstance
NonConfigurationInstances nc =
(NonConfigurationInstances) getLastNonConfigurationInstance();
if (nc != null) {
viewModelStore = nc.viewModelStore;
}
}
if (viewModelStore == null && custom == null) {
return null;
}
NonConfigurationInstances nci = new NonConfigurationInstances();
nci.custom = custom;
nci.viewModelStore = viewModelStore;
return nci;
}
onRetainNonConfigurationInstance()は、ViewModelStroeを持つComponentActivityを作成しました.NonConfigurationInstanceオブジェクトは、Activity破棄再作成を追跡し、ViewModelは変わらないプロセスを維持します.まとめ:1、Activity破棄時にActivity.retainNonConfigurationInstances()Activityを作成する.NonConfigurationInstaceオブジェクトはActivity ClientRcordに渡されて保存され、Activity.NoConfigurationInstance.义齿NonConfigurationInstanceオブジェクト、ComponentActivity.NonConfigurationInstanceは、ViewModelStore 2、Activity作成後、Activityを持つ.attch()では、Activity ClientRcordが持つActivity.NonConfiguration InstaceオブジェクトはActivityに割り当てられます.mLastNonConfigurationInstances 3は、ViewModelProvidersを呼び出す.of()の場合、ComponentActivityが呼び出されます.getViewModelStore()は、getViewModelStore()で2のmLastNonConfigurationInstancesでComponentActivityを取得します.NonConfigurationInstanceオブジェクト、およびComponentActivity.NonConfigurationInstanceが所有するViewModelStoreが返されます.これによりActivity破棄の再作成が保証され、ViewModelStoreはその破棄前のViewModelStoreなので、
ViewModelProviders.of(target, factory).get(ViewModel.class)
で取得したのもActivity破棄前のViewModelです.FragmentがViewModelStoreをどのように管理するか
Fragment.getViewModelStore()は、次のように実装されます.
public ViewModelStore getViewModelStore() {
if (mFragmentManager == null) {
throw new IllegalStateException("Can't access ViewModels from detached fragment");
}
return mFragmentManager.getViewModelStore(this);
}
fragment自身はView Modelを直接管理せず、エージェントFragmentManagement.を通じてgetView Model()はView Modelに戻り、次にFragmentMangerを見ます.getViewModelの実装:FragmentManagerImpl.getViewModel()
ViewModelStore getViewModelStore(@NonNull Fragment f) {
return mNonConfig.getViewModelStore(f);
}
FragmentManagerImplはまたmNonConfigを通じてView ModelStoreを管理し、mNonConfigがいつ作成されたかを見てみましょう.
public void attachController(@NonNull FragmentHostCallback host,
@NonNull FragmentContainer container, @Nullable Fragment parent) {
if (mHost != null) throw new IllegalStateException("Already attached");
mHost = host;
mContainer = container;
mParent = parent;
if (parent != null) {
mNonConfig = parent.mFragmentManager.getChildNonConfig(parent);
} else if (host instanceof ViewModelStoreOwner) {
ViewModelStore viewModelStore = ((ViewModelStoreOwner) host).getViewModelStore();
mNonConfig = FragmentManagerViewModel.getInstance(viewModelStore);
} else {
mNonConfig = new FragmentManagerViewModel(false);
}
}
FragmentがサブFragmentであるか、ActivityがViewModelStoreOwnerを実現しているかによって、1、FragmentルートFragmentでActivityがViewModelStoreOwnerインタフェースを実現する場合、Activity.getViewModelStoreはviewModelStoreを取得します.上記の分析から、このviewModelStoreは再作成前のviewModelStoreを破棄していることがわかります.mNonConfigはViewModelなので、viewModelStoreで取得したmNonConfigも再構築前のmNonCofigを破棄しています.2、fragmentが子fragmentの場合、mNonConfigは親FragmentのmNonConfigから取得し、activityがViewModelStoreOwnerを実現した場合、1に戻り、mNonCofigは破棄前のmNonCofigである.ActivityがViewModelStoreOwnerを実装していない場合は、3に戻ります.3.ActivityがViewModelStoreOwnerを実装場合、新しいmNonConfigを新規作成する.mNonConfigは破棄前のmNonConfigであるため、mNonConfigによって管理されるViewModelStoreも当然破棄前のViewModelStoreである.このことからfragmentのviewModeStoreを保証する際に破棄する前のViewModelStoreはActivityの実現に依存していることがわかる.