Share
Embed
Android-ViewModel.pdf
Androd TipTip
2018. 11. 25(Sun) Introduction in Android AAC-ViewModel
TaeHwan
November 25, 2018
Transcript
56 slides
-
ࣗѐ • GDG Seoul • ٘۽٘ աஎ •
RGP Korea • ਃӝਃ উ٘۽٘ ѐߊ • Blog : Է ݆ ѐߊо غ ! (https://thdev.tech) -
ViewModel ੜ ঌӝ • ViewModel ҳઑ ঌӝ • ViewModelਸ ٜ݅ӝ
ਤೠ بҳ • ViewModelਸ ੜ ഝਊೞӝ ਤೠ ܻ࠙ • ܻ࠙ೞ ࠁݶ ࢤӝח Ҋ • ؊ ա ViewModel -
ViewModel View Model DataBinding and commands ViewModel updates the model
Send notifications Send notifications ViewModel ҳઑ ঌӝ -
ViewModelਸ ٜ݅ӝ ਤೠ بҳ • View ViewModel р ҙ҅ܳ ױ
दఃӝ ਤೠ ݾ • DI(Dagger, koin) ഝਊೞৈ Ѿبܳ ੋ. • DataBinding ഝਊਵ۽ View৬ ઓبܳ ੋ. -
ViewModelਸ ੜ ഝਊೞӝ ਤೠ ܻ࠙ • ViewModelҗ Model ೡী ٮۄ
୭ೠ ܻ࠙ೠ • ܻ࠙ೡ ࣻ ח ೠ ୭۽ ܻ࠙ೞৈ, ৮ೠ Factory pattern ୶ҳ -
ܻ࠙ೞ ࠁݶ ࢤӝח Ҋ • അप DataBinding Ѿبо ֫ইઉ ৮ೠ
ഋకܳ ٜ݅ӝ औ ঋ • ழझథ ࠭৬ DataBindingਸ ୭ೠ ഝਊೞח ഋక۽ ࢸ҅ೡ ਃо -
؊ ա ViewModel • ղࠗীࢲ ࢎਊೞח Rx/Coroutines ١ਸ ਤೠ ۄ
ࢎਸ ٮܰب۾ ࢸ҅ೡ ਃо • Lifecycle ਊೞח ഋక۽ ѐߊ ਃ • AAC-ViewModelਸ ഝਊೞѢա -
AAC-ViewModel ݾ • The ViewModel class is designed to store
and manage UI-related data in a lifecycle conscious way. The ViewModel class allows data to survive configuration changes such as screen rotations. • Android AAC ViewModel ചݶ ഥ द ؘఠܳ ਬೡ ࣻ ח ҳઑ۽ ٣ੋೞਵݴ, Android Lifecycle onDestroy() ٘о زೠ. https://developer.android.com/topic/libraries/architecture/viewmodel -
AAC-ViewModel ܻೞݶ • ݾ : ചݶ ഥ द ؘఠ ਬܳ
ਤೠ ҳઑ۽ ViewModelਸ ٣ੋ • Activity/Fragment Lifecycleী ٮۄ ViewModel ਬܳ ೞҊ . • ղࠗীࢲ Lifecycleਸ ࢎਊೡ ࣻ ب۾ ୡӝചೞҊ ਵݴ, onDestroy() ز द ViewModel ղ ࠗ onCleared() ഐਸ ా೧ Releaseܳ ਬبೠ. -
AAC-ViewModel • AAC ViewModel Androidীࢲ ࢎਊ оמೞ݅ • MSDN ViewModelҗח
ইޖ ࢚ҙহҊ, Ӓր ܴ ݅ ViewModelਸ ঌҊ о • উ٘۽٘ ѐߊ ಞࢿਸ ୶ҳೞח ViewModel ب۽ ঈೞ • ಞ࢚ Application ੑ оמೞҊ • ಞ࢚ AAC-ViewModel ؘఠ ਬب ೧ળ -
AAC-ViewModel • AAC-ViewModel ইې 2ѐ۽ ࢚ࣘ߉ই ҳഅೠ • ViewModel() •
AndroidViewModel(application) -
AAC-ViewModel class SharedViewModel : ViewModel() { val selected = MutableLiveData<Item>()
fun select(item: Item) { selected.value = item } } -
AAC-ViewModel ୡӝച • AAC-ViewModel ୡӝചח ViewModelProviders۽ ୡӝചೠ • Activity/Fragment 2ѐ
ী ೞա۽ ୡӝച оמ • ӝࠄ ViewModel ࢤࢿ ߧਤܳ ߩযաݶ Factoryܳ ࢚ࣘ߉ই ߹ب ҳഅ೧ঠ ೠ -
AAC-ViewModel class MasterFragment : Fragment() { private lateinit var itemSelector:
Selector private lateinit var model: SharedViewModel override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) model = activity?.run { ViewModelProviders.of(this).get(SharedViewModel::class.java) } ?: throw Exception("Invalid Activity") itemSelector.setOnClickListener { item -> // Update the UI } } } ViewModelProviders.of(this) -
ViewModelProviders.of(this) • thisী Activity/Fragment۽ ୡӝചо оמ • Activity ࢎਊ द
Activity Lifecycleਸ ٮܲ • Fragment ࢎਊ द Fragment Lifecycleਸ ٮܲ -
ViewModelProviders.of(this) ӝࠄ @NonNull @MainThread public static ViewModelProvider of(@NonNull Fragment
fragment) { return of(fragment, null); } @NonNull @MainThread public static ViewModelProvider of(@NonNull FragmentActivity activity) { return of(activity, null); } -
ViewModelProviders.of(this) Factory @NonNull @MainThread 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); } @NonNull @MainThread 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); } fragment.getViewModelStore() activity.getViewModelStore() ViewModelStore()ܳ ా೧ ӝઓ ViewModel ࢤࢿ ؘఠо թওח ViewModelStore()ܳ ా೧ ӝઓ ViewModel ࢤࢿ ؘఠо թওח -
Fragment.java @NonNull @Override public ViewModelStore getViewModelStore() { if (getContext() ==
null) { throw new IllegalStateException("Can't access ViewModels from detached fragment"); } if (mViewModelStore == null) { mViewModelStore = new ViewModelStore(); } return mViewModelStore; } -
FragmentActivity.java @NonNull @Override 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; } -
ViewModelStore.java 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); } /** * Clears internal storage and notifies ViewModels that they are no longer used. */ public final void clear() { for (ViewModel vm : mMap.values()) { vm.onCleared(); } mMap.clear(); } } -
ѾҴ • ViewModelStore.java • ActivityFragment.java/Fragment.javaীࢲ ViewModelStore.javaܳ оҊ. • Activity/Fragmentীࢲ ਃೠ
ViewModelStoreܳ HashMapਵ۽ ࠁҙೞҊ, ܳ оઉৡ -
AAC-ViewModel class MasterFragment : Fragment() { private lateinit var itemSelector:
Selector private lateinit var model: SharedViewModel override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) model = activity?.run { ViewModelProviders.of(this).get(SharedViewModel::class.java) } ?: throw Exception("Invalid Activity") itemSelector.setOnClickListener { item -> // Update the UI } } } ViewModelProviders.of(this) get(SharedViewModel::class.java) -
get(SharedViewModel::class.java) • Activity/Fragmentীࢲ ࠁҙ ੋ ViewModelStore ёܳ ਊೞৈ getਸ ܻ
• getীࢲח ࢜۽ ёܳ ࢤࢿೞѢա, ViewModelStoreী ӝઓ ёܳ द ࠛ۞ৡ • HashMapী ೞӝ ਤೠ Ҋਬఃܳ ೠ. -
get(Class<T>) / Ҋਬః @NonNull @MainThread public <T extends ViewModel> T
get(@NonNull Class<T> modelClass) { String canonicalName = modelClass.getCanonicalName(); if (canonicalName == null) { throw new IllegalArgumentException("Local and anonymous classes can not be ViewModels"); } return get(DEFAULT_KEY + ":" + canonicalName, modelClass); } private static final String DEFAULT_KEY = "androidx.lifecycle.ViewModelProvider.DefaultKey"; Default৬ canonicalNameਸ Ҋਬః ࢤࢿ Package name.SharedViewModel -
get(Key, Class<T>) @NonNull @MainThread 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; } ViewModelStore۽ࠗఠ getValue viewModel null ইפݶ return nullݶ ViewModelFactory۽ࠗఠ new Factoryח ӝࠄ ViewModelFactory о ઓ ViewModelStoreী put -
ViewModelFactory @NonNull @MainThread 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); } @NonNull @MainThread 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); } fragment.getViewModelStore() activity.getViewModelStore() Factory ܳ ೞ ঋਵݶ AndroidViewModelFactoryࢎਊ Factory ܳ ೞ ঋਵݶ AndroidViewModelFactoryࢎਊ if (factory == null) { factory = ViewModelProvider.AndroidViewModelFactory.getInstance(application); } if (factory == null) { factory = ViewModelProvider.AndroidViewModelFactory.getInstance(application); } -
ViewModelFactory Application ೞա݅ ਸ ҃ /** * {@link Factory} which
may create {@link AndroidViewModel} and * {@link ViewModel}, which have an empty constructor. */ public static class AndroidViewModelFactory extends ViewModelProvider.NewInstanceFactory { private static AndroidViewModelFactory sInstance; /** * Retrieve a singleton instance of AndroidViewModelFactory. * * @param application an application to pass in {@link AndroidViewModel} * @return A valid {@link AndroidViewModelFactory} */ @NonNull public static AndroidViewModelFactory getInstance(@NonNull Application application) { if (sInstance == null) { sInstance = new AndroidViewModelFactory(application); } return sInstance; } private Application mApplication; /** * Creates a {@code AndroidViewModelFactory} * * @param application an application to pass in {@link AndroidViewModel} */ public AndroidViewModelFactory(@NonNull Application application) { mApplication = application; -
ViewModelFactory ࢤࢿо হח ҃ public static class NewInstanceFactory implements Factory
{ @SuppressWarnings("ClassNewInstance") @NonNull @Override public <T extends ViewModel> T create(@NonNull Class<T> modelClass) { //noinspection TryWithIdenticalCatches try { return modelClass.newInstance(); } catch (InstantiationException e) { throw new RuntimeException("Cannot create an instance of " + modelClass, e); } catch (IllegalAccessException e) { throw new RuntimeException("Cannot create an instance of " + modelClass, e); } } } -
ViewModelFactory ழझథ ࢤࢿо ݶ? class SharedViewModelFactory(data data data) : ViewModelProvider.Factory
{ override fun <T : ViewModel?> create(modelClass: Class<T>): T { return SharedViewModel(data, data, data) as T } } ViewModelProviders.of(this, SharedViewModelFactory(data, data, data)).get(SharedViewModel::class.java) -
ViewModel clear • ઁ AAC-ViewModel clear ೡө? • Activity/Fragment Lifecycleੋ
onDestroy()ীࢲ ഛੋ оמ -
FragmentActivity.java /** * Destroy all fragments. */ @Override protected void
onDestroy() { super.onDestroy(); if (mViewModelStore != null && !isChangingConfigurations()) { mViewModelStore.clear(); } mFragments.dispatchDestroy(); } -
FragmentActivity.java /** * Called when the fragment is no longer
in use. This is called * after {@link #onStop()} and before {@link #onDetach()}. */ @CallSuper public void onDestroy() { mCalled = true; FragmentActivity activity = getActivity(); boolean isChangingConfigurations = activity != null && activity.isChangingConfigurations(); if (mViewModelStore != null && !isChangingConfigurations) { mViewModelStore.clear(); } } -
ViewModelStore.java /** * Clears internal storage and notifies ViewModels that
they are no longer used. */ public final void clear() { for (ViewModel vm : mMap.values()) { vm.onCleared(); } mMap.clear(); } -
ViewModel.java public abstract class ViewModel { /** * This method
will be called when this ViewModel is no longer used and will be destroyed. * <p> * It is useful when ViewModel observes some data and you need to clear this subscription to * prevent a leak of this ViewModel. */ @SuppressWarnings("WeakerAccess") protected void onCleared() { } } -
ਬਊೠ ViewModel? • Activity ചݶ ഥ द ؘఠ ਬо ਃೠ
҃ ਬਊೞ. • 1ѐ Activityীࢲ Fragmentীࢲ زੌೠ ߮/ؘఠܳ ܻೞҊ रਸ ҃ • onClearedীࢲ releaseо ਃೞ -
1ѐ Activityীࢲ Fragment • Fragmentীࢲ fragmentо ইצ activityܳ ֈѹળ.
• ViewModelProviders.of(activity).get(SharedViewModel::class.java) -
RxJava disposable abstract class BaseViewModel : ViewModel() { val disposable:
CompositeDisposable = CompositeDisposable() override fun onCleared() { super.onCleared() disposable.clear() } } -
Coroutines cancel abstract class BaseViewModel : ViewModel(), CoroutineScope { val
job: Job = Job() override val coroutineContext: CoroutineContext get() = Dispatchers.Default + job override fun onCleared() { super.onCleared() job.cancel() } }