Upgrade to Pro — share decks privately, control downloads, hide ads and more …

How ViewModel is retained even when the screen rotates

sho5nn
December 11, 2018

How ViewModel is retained even when the screen rotates

sho5nn

December 11, 2018
Tweet

More Decks by sho5nn

Other Decks in Programming

Transcript

  1. class HogeActivity : AppCompatActivity { override fun onCreate(savedInstanceState: Bundle?) {

    super.onCreate(savedInstanceState) Log.d(TAG, "onCreate") val activity: FragmentActivity = this val factory : ViewModelProvider.Factory = ViewModelProvider.NewInstanceFactory() val viewModel = ViewModelProvider(activity, factory).get(FooViewModel::class.java) Log.d(TAG, " - Activity :${this.hashCode()}") Log.d(TAG, " - ViewModel:${viewModel.hashCode()}") } } 6
  2. // Activity ͕ىಈͨ͠ onCreate - Activity :132818886 - ViewModel:249530701 onStart

    onResume // Activity ͕ճసͨ͠ onPause onStop onRetainNonConfigurationInstance onDestroy onCreate - Activity :103312713 - ViewModel:249530701 <- ಉ͡ ViewModel Ͱ͋Δ͜ͱ͕Θ͔Δ onStart onResume 7
  3. ͸ͳ͢͜ͱ - ViewModelProvider - ViewModelStore - FragmentActivity implements ViewModelStoreOwner -

    Activity - getLastNonConfigurationInstance() - onRetainNonConfigurationInstance() - ·ͱΊ 8
  4. લఏ৚݅ dependencies { implementation 'androidx.appcompat:appcompat:1.0.2' ... } +--- androidx.appcompat:appcompat:1.0.2 |

    +--- androidx.fragment:fragment:1.0.0 | | \--- androidx.lifecycle:lifecycle-viewmodel:2.0.0 (*) ... 9
  5. લఏ৚݅ class HogeActivity : AppCompatActivity { override fun onCreate(savedInstanceState: Bundle?)

    { super.onCreate(savedInstanceState) val activity: FragmentActivity = this val factory : ViewModelProvider.Factory = ViewModelProvider.NewInstanceFactory() val viewModel = ViewModelProvider(activity, factory).get(FooViewModel::class.java) } } ͜ͷίʔυΛ΋ͱʹɺ࢓૊ΈΛ௥͍͖ͬͯ·͢ɻ 10
  6. package androidx.lifecycle; public class ViewModelProvider { public interface Factory {

    @NonNull <T extends ViewModel> T create(@NonNull Class<T> modelClass); } private final Factory mFactory; private final ViewModelStore mViewModelStore; public ViewModelProvider(@NonNull ViewModelStoreOwner owner, @NonNull Factory factory) { this(owner.getViewModelStore(), factory); } public ViewModelProvider(@NonNull ViewModelStore store, @NonNull Factory factory) { mFactory = factory; this.mViewModelStore = store; } ... } 12
  7. package androidx.lifecycle; public class ViewModelProvider { private final ViewModelStore mViewModelStore;

    public <T extends ViewModel> T get(@NonNull String key, @NonNull Class<T> 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; } ... } 13
  8. package androidx.lifecycle; public class ViewModelStore { private final HashMap<String, ViewModel>

    mMap = new HashMap<>(); final void put(String key, ViewModel viewModel) { ViewModel oldViewModel = mMap.put(key, viewModel); if (oldViewModel != null) { oldViewModel.onCleared(); } } final ViewModel get(String key) { return mMap.get(key); } public final void clear() { for (ViewModel vm : mMap.values()) { vm.onCleared(); } mMap.clear(); } } 15
  9. package androidx.lifecycle; public class ViewModelProvider { private final ViewModelStore mViewModelStore;

    public <T extends ViewModel> T get(@NonNull String key, @NonNull Class<T> 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; } ... } 16
  10. class HogeActivity : AppCompatActivity { override fun onCreate(savedInstanceState: Bundle?) {

    super.onCreate(savedInstanceState) val activity: FragmentActivity = this val factory : ViewModelProvider.Factory = ViewModelProvider.NewInstanceFactory() val viewModel = ViewModelProvider(activity, factory).get(FooViewModel::class.java) } } 17
  11. package androidx.lifecycle; public class ViewModelProvider { private final ViewModelStore mViewModelStore;

    public ViewModelProvider(@NonNull ViewModelStoreOwner owner, @NonNull Factory factory) { this(owner.getViewModelStore(), factory); } public ViewModelProvider(@NonNull ViewModelStore store, @NonNull Factory factory) { mFactory = factory; this.mViewModelStore = store; } } 18
  12. package androidx.fragment.app; public class FragmentActivity extends ComponentActivity implements ViewModelStoreOwner ...

    { private ViewModelStore mViewModelStore; @NonNull @Override public ViewModelStore getViewModelStore() { ... 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; } } 21
  13. package androidx.fragment.app; public class FragmentActivity extends ComponentActivity implements ViewModelStoreOwner ...

    { private ViewModelStore mViewModelStore; @NonNull @Override public ViewModelStore getViewModelStore() { ... if (mViewModelStore == null) { NonConfigurationInstances nc = (NonConfigurationInstances) getLastNonConfigurationInstance(); ... } } static final class NonConfigurationInstances { Object custom; ViewModelStore viewModelStore; FragmentManagerNonConfig fragments; } } 22
  14. package android.app; public class Activity extends ContextThemeWrapper implements ... {

    /* package */ NonConfigurationInstances mLastNonConfigurationInstances; @Nullable public Object getLastNonConfigurationInstance() { return mLastNonConfigurationInstances != null ? mLastNonConfigurationInstances.activity : null; } static final class NonConfigurationInstances { Object activity; HashMap<String, Object> children; FragmentManagerNonConfig fragments; ArrayMap<String, LoaderManager> loaders; VoiceInteractor voiceInteractor; } } 24
  15. https://developer.android.com/reference/android/app/Activity.html#getLastNonConfigurationInstance() Retrieve the non-configuration instance data that was previously returned

    by onRetainNonConfigurationInstance(). This will be available from the initial onCreate(Bundle) and onStart() calls to the new instance, allowing you to extract any useful dynamic state from the previous instance. 25
  16. https://developer.android.com/reference/android/app/Activity#onRetainNonConfigurationInstance() Called by the system, as part of destroying an

    activity due to a configuration change, when it is known that a new instance will immediately be created for the new configuration. You can return any object you like here, including the activity instance itself, which can later be retrieved by calling getLastNonConfigurationInstance() in the new activity instance. 27
  17. package android.app; public class Activity extends ContextThemeWrapper implements ... {

    public Object onRetainNonConfigurationInstance() { return null; } ... } 28
  18. package androidx.fragment.app; public class FragmentActivity extends ComponentActivity implements ViewModelStoreOwner, ...

    { private ViewModelStore mViewModelStore; @Override public final Object onRetainNonConfigurationInstance() { Object custom = onRetainCustomNonConfigurationInstance(); FragmentManagerNonConfig fragments = mFragments.retainNestedNonConfig(); if (fragments == null && mViewModelStore == null && custom == null) { return null; } NonConfigurationInstances nci = new NonConfigurationInstances(); nci.custom = custom; nci.viewModelStore = mViewModelStore; nci.fragments = fragments; return nci; } } 29
  19. package androidx.fragment.app; public class FragmentActivity extends ComponentActivity implements ViewModelStoreOwner ...

    { private ViewModelStore mViewModelStore; @SuppressWarnings("deprecation") @Override protected void onCreate(@Nullable Bundle savedInstanceState) { mFragments.attachHost(null /*parent*/); super.onCreate(savedInstanceState); NonConfigurationInstances nc = (NonConfigurationInstances) getLastNonConfigurationInstance(); if (nc != null && nc.viewModelStore != null && mViewModelStore == null) { mViewModelStore = nc.viewModelStore; } ... } } 30
  20. ·ͱΊ class HogeActivity : AppCompatActivity { override fun onCreate(savedInstanceState: Bundle?)

    { super.onCreate(savedInstanceState) val activity: FragmentActivity = this val factory : ViewModelProvider.Factory = ViewModelProvider.NewInstanceFactory() val viewModel = ViewModelProvider(activity, factory).get(FooViewModel::class.java) } } 31
  21. ·ͱΊ 1/3 ճసલ - FragmentActivity#onCreate() - ͜ͷ࣌఺Ͱ͸·ͩ FragmentActivity ͷ mViewModelStore

    ͸ null - HogeActivity#onCreate() - ViewModelProvider ΠϯελϯεΛੜ੒͢Δ - ͜ͷ࣌఺Ͱɺ FragmentActivity#getViewModelStore() ͕ݺ͹ΕΔͨΊ FragmentActivity ͷ mViewModelStore ʹΠϯελϯε͕୅ೖ͞Ε͍ͯΔ - ViewModelProvider#get() ͔Β ViewModel ͷΠϯελϯεΛऔಘͰ͖Δ - ͜ͷ ViewModel ͷΠϯελϯε͸ɺ FragmentActivity ͕࣋ͭ mViewModelStore ʹ֨ೲ͞Ε͍ͯΔ 32
  22. ·ͱΊ 3/3 ճసޙ - FragmentActivity#onCreate() - Activity#getLastNonConfigurationInstance() ͔ΒɺNonConfigurationInstances ΫϥεͷΠϯελ ϯεΛऔಘ͍ͯ͠Δ

    - NonConfigurationInstances ΫϥεͷΠϯελϯεʹ֨ೲ͞Ε͍ͯΔɺճసલͷ FragmentActivity ͕ ͍࣋ͬͯͨ ViewModelStore Λɺ ճసޙͷ FragmentActivity ͸ࣗ਎ͷ ViewModelStore ʹ୅ೖͯ͠ ͍Δ - HogeActivity#onCreate() - ViewModelProvider ΠϯελϯεΛੜ੒͢Δ - ͜ͷ࣌఺Ͱɺ FragmentActivity ͸ɺճసલͷ ViewModelStore ΠϯελϯεΛ͍࣋ͬͯΔ - ViewModelProvider#get() ͔Β ViewModel ͷΠϯελϯεΛऔಘͰ͖Δ - ͜ͷ ViewModel ͸ɺ FragmentActivity ͕࣋ͭ ViewModelStore ʹ֨ೲ͞Ε͍ͯΔΠϯελϯεͰ͋ Γɺ͔ͭɺ ճసલʹੜ੒͞Ε͍ͯͨ ViewModel Ͱ͋Δ ! 34