ViewModel of AAC

ViewModel of AAC

Introduction to ViewModel of Android Architecture Components

6dd0483f1353a4a359e92633cfd65c64?s=128

Daichi Furiya (Wasabeef)

February 22, 2018
Tweet

Transcript

  1. Architecture Components ษڧձ ͕͑Θ Θ͞ͼʔ; ͋Β͖ ͋Μ͍͟Ώ͖ ୈ3ճ໨ ViewModel

  2. Architecture Componentsษڧձ ͱ͸ • Architecture Componentsͷجૅ஌ࣝʹֶ͍ͭͯͿษڧձ • ओ࠵ɿGDG Tokyo ϋογϡλά:

    #gdgtokyo • ߨࢣɺνϡʔλʔɿGoogleࣾһͱGoogle Developer Expert ʢ͋Μ͍͟Ώ͖ɺ ͕͑ΘɺΘ͞ͼʔ;ɺ͋Β͖ʣ • ౰೔νϡʔλʔɿ
 ɹ@satorufujiwaraɺ@STAR_ZEROɺ@95kugoɺ@zaki50ɺ@itog
  3. Architecture Componentsษڧձ ͱ͸ • ܭ4ճͷ༧ఆ • ୈ1ճ:Handling Lifecycles • ୈ2ճ:LiveData

    • ୈ3ճ:ViewModel • ୈ4ճ:Room λΠϜςʔϒϧ 19:30ʙ19:35 ѫࡰˍઆ໌ 19:35ʙ20:15 ViewModel ͷઆ໌ 20:15ʙ20:25 ٳܜ 20:25ʙ ՝୊औΓ૊Έ
  4. Download Android Studio 3.0.1 https://goo.gl/KmYZzW

  5. Architecture Components ͱ͸ • ෳ਺ͷػೳɾϥΠϒϥϦͷ૯শ • Lifecycles • LiveData •

    ViewModel • Room • Paging
  6. Architecture Components ͱ͸ • ෳ਺ͷػೳɾϥΠϒϥϦͷ૯শ • Lifecycles • LiveData •

    ViewModel • Room • Paging ݸผར༻OK
  7. Architecture Components ͱ͸ • ෳ਺ͷػೳɾϥΠϒϥϦͷ૯শ • Lifecycles • LiveData •

    ViewModel • Room • Paging ݸผར༻OK ૊Έ߹Θͤར༻OK
  8. Architecture Components ͱ͸ • ෳ਺ͷػೳɾϥΠϒϥϦͷ૯শ • Lifecycles • LiveData •

    ViewModel • Room • Paging ࠓ೔ͷςʔϚ͸͜Ε લճ ࣍ճ * RxJava * ReactiveStreams * Dagger ʹ͍ͭͯ͸ࠓճ͸औΓ্͛·ͤΜ
  9. Architecture Components ͱ͸ • Google I/O 2017 Ͱൃදʢ1.0.0 alpha 1ʣ

    • ݱࡏͷ҆ఆόʔδϣϯ : 1.1.0 ʢ2018೥2݄22೔ʣ https://developer.android.com/topic/libraries/architecture/release-notes.html
  10. Architecture Components ͷઃఆ dependencies { // ViewModel and LiveData implementation

    “android.arch.lifecycle:extensions:x.y.z" kapt “android.arch.lifecycle:compiler:x.y.z” } ϓϩδΣΫτͷ build.gradle https://developer.android.com/topic/libraries/architecture/adding-components.html
  11. None
  12. Lifecycles ͓͞Β͍

  13. Lifecycles • Lifecycles = Lifecycle-aware Components • ϥΠϑαΠΫϧΛݕ஌͢Δίϯϙʔωϯτ • Activity

    ΍ Fragment ͷϥΠϑαΠΫϧঢ়ଶ͕มΘͬͨͱ͖ʹԿ͔ ΞΫγϣϯΛى͜͢ɺͱ͍͏͜ͱ͕Ͱ͖ΔΑ͏ʹͳΔ
  14. Lifecycle.State • ݱࡏͷϥΠϑαΠΫϧঢ়ଶΛද͢ enum • INITIALIZED • DESTROYED • CREATED

    • STARTED • RESUMED https://developer.android.com/topic/libraries/architecture/lifecycle.html
  15. Lifecycle.Event • ϥΠϑαΠΫϧঢ়ଶ͕มΘͬͨ࣌ͷΠϕϯτΛද͢ enum https://developer.android.com/topic/libraries/architecture/lifecycle.html • ON_CREATE • ON_START •

    ON_RESUME • ON_PAUSE • ON_STOP • ON_DESTROY • ON_ANY
  16. ݱࡏͷϥΠϑαΠΫϧΛऔಘ΍؂ࢹ͢Δ val state: Lifecycle.State = lifecycle.currentState // state.compareTo(Lifecycle.State.INITIALIZED) lifecycle.addObserver(object :

    LifecycleObserver { @OnLifecycleEvent(Event.ON_ANY) fun onAny(source: LifecycleOwner, event: Event) { // ... } })
  17. LiveData ͓͞Β͍

  18. ओͳLiveData • LiveData (android.arch.lifecycle) ௨ৗͷ LiveData • MutableLiveData (android.arch.lifecycle) ֎෦͔ΒมߋՄೳͳ

    LiveData • MediatorLiveData (android.arch.lifecycle) ෳ਺ͷ LiveData ΛଋͶͯ؅ཧ͢Δ LiveData
  19. ViewModel

  20. ViewModel • Activity ͷը໘ճస࣌ͷσʔλอ࣋ • Activity ͷෳ਺ Fragment ؒͰͷσʔλड͚౉͠ •

    LiveData ͱซ༻͢Δ͜ͱ͕ଟ͍ • ϓϩηεఀࢭޙ͸෮چͰ͖ͳ͍ • σʔλͷӬଓԽͰ͸ͳ͍
  21. ViewModel

  22. ͜Ε·Ͱͷը໘ճసରԠ͸ʁ

  23. ͜Ε·Ͱͷը໘ճసରԠ͸ʁ • Activity#onSaveInstanceState() • FragmentActivity#onRetainCustomNonConfigurationInstance() • Fragment#setRetainInstance() • android:configChanges="orientation|keyboardHidden" •

    ݻఆ…
  24. Activity#onSaveInstanceState()

  25. class BeefActivity : AppCompatActivity() { companion object { private const

    val EXTRA_BEEF_KEY = "8044" } // ... public override fun onSaveInstanceState(outState: Bundle) { outState.putString(EXTRA_BEEF_KEY, beef.text as String) super.onSaveInstanceState(outState) } override fun onRestoreInstanceState(savedInstanceState: Bundle) { super.onRestoreInstanceState(savedInstanceState) beef.text = savedInstanceState.getString(EXTRA_BEEF_KEY) } } Activity#onSaveInstanceState() onRestoreInstanceStateͰ͸ͳ͘onCreate()Ͱ΋Մ
  26. Activity#onSaveInstanceState() • ը໘ճస΍ΞϓϦόοΫάϥϯυޙͷϓϩηεఀࢭ͔Βσʔ λΛ෮چͰ͖Δɻ • ୯७Ͱগྔͷσʔλ޲͖
 ʢEditText ͷೖྗσʔλอ࣋΍εΫϩʔϧҐஔͳͲʣ • େ͖͍σʔλ΍ෳࡶͳσʔλ͸

    Configuration Change தʹ ύϑΥʔϚϯε௿Լʹͭͳ͕Δ
  27. FragmentActivity# onRetainCustomNonConfigurationInstance()

  28. onRetainCustomNonConfigurationInstance() class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?)

    { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) } }
  29. onRetainCustomNonConfigurationInstance() class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?)

    { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) } override fun onRetainCustomNonConfigurationInstance(): Any { return Dog("chip", 6) } } data class Dog(val name: String, val age: Int) อ͍࣋ͨ͠ΠϯελϯεΛฦ٫
  30. onRetainCustomNonConfigurationInstance() class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?)

    { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) val dog = lastCustomNonConfigurationInstance as Dog? ?: Dog("wasa", 18) } override fun onRetainCustomNonConfigurationInstance(): Any { return Dog("chip", 6) } } data class Dog(val name: String, val age: Int) औಘ
  31. onRetainCustomNonConfigurationInstance() • ը໘ճసޙͷσʔλ෮چͰ͖Δɻ • όοΫάϥϯυޙͷϓϩηεఀࢭ͔Β͸σʔλ෮چͰ ͖ͳ͍ • ը૾ͳͲͷେ͖ͳσʔλ΍ෳࡶͳσʔλ΋อ࣋Ͱ͖Δ • ͓खܰͳؾ͕͢Δ

  32. Fragment#setRetainInstance()

  33. @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) public class HolderFragment extends Fragment ɹɹɹɹɹɹɹɹɹɹɹɹɹɹɹɹɹimplements ViewModelStoreOwner { private

    static final String LOG_TAG = "ViewModelStores"; // ... public HolderFragment() { setRetainInstance(true); } // ... } Fragment#setRetainInstance() AACͷ಺෦࣮૷ΛҰ෦ൈਮ
  34. Fragment#setRetainInstance() • ը໘ճసޙͷσʔλ෮چͰ͖Δɻ • όοΫάϥϯυޙͷϓϩηεఀࢭ͔Β͸σʔλ෮چͰ ͖ͳ͍ • ը૾ͳͲͷେ͖ͳσʔλ΍ෳࡶͳσʔλ΋อ࣋Ͱ͖Δ • ViewModel

    ͷ಺෦࣮૷Ͱ࢖ΘΕ͍ͯΔ
  35. ViewModel

  36. ViewModelͷܧঝ ୯७ʹViewModelΛܧঝ͢Δ # View΍ActivityContext͸࣋ͬͯ͸͍͚ͳ͍ data class User(val name: String, val

    age: Int) class UserViewModel : ViewModel() { private var user: MutableLiveData<User>? = null fun getUser() { if (user == null) { user = MutableLiveData() load() } } private fun load() { // ... } }
  37. ViewModelΛΠϯελϯεԽ val user = ViewModelProviders.of(this).get(UserViewModel::class.java) user.getUser()?.observe(this, Observer { it ->

    // Log.d("BEEF", "$it") }) ViewModelProvidersΛ࢖ͬͯΠϯελϯεԽ͢Δ # ৄࡉ͸ޙड़
  38. class UserViewModel : ViewModel() { // ... } ViewModel#onCleared()ͰϦʔΫ๷ࢭ

  39. class UserViewModel : ViewModel() { var disposables = CompositeDisposable() //

    ... override fun onCleared() { super.onCleared() // ϦʔΫ๷ࢭ౳ɺղ์͢Δ৔߹͸͜͜Ͱɻ disposables.dispose() } } ViewModel#onCleared()ͰϦʔΫ๷ࢭ
  40. AndroidViewModel

  41. AndroidViewModelͷܧঝ class DogsViewModel(app: Application) : AndroidViewModel(app) { @Inject lateinit var

    repo: DogRepository var dogs: MutableLiveData<Dogs>? = null init { // (app as BeefApp).applicationInjector() as AppComponent } // ... } ViewModel಺ͰApplication͕ඞཁͳ৔߹ʹ࢖͑Δ
  42. AndroidViewModelΛΠϯελϯεԽ val dogs = ViewModelProviders.of(this).get(DogsViewModel::class.java) dogs.getUser()?.observe(this, Observer { it ->

    // Log.d("DACHSHUND", "$it") }) લड़ͷViewModelͱҰॹͰ͢ # ৄࡉ͸ޙड़
  43. ViewModelProvider /s

  44. ViewModelProvider /sͰΠϯελϯεԽ val user = ViewModelProviders.of(this).get(UserViewModel::class.java) ViewModel͸ViewModelProviderܦ༝Ͱ ΠϯελϯεԽ͠ͳ͚Ε͹͍͚·ͤΜ val user

    = UserViewModel()
  45. val user = ViewModelProviders.of(this) .get(UserViewModel::class.java) val user = ViewModelProviders.of(<FragmentActivity ||

    Fragment>) .get(<T : ViewModel>::class.java) ViewModelProvider /s ViewModelProviders.of()ʹࢦఆͰ͖Δͷ͸ FragmentActivity͔Fragment͚ͩ
  46. ViewModelProviders#of() @NonNull @MainThread public static ViewModelProvider of(@NonNull Fragment fragment) {}

    @NonNull @MainThread public static ViewModelProvider of(@NonNull FragmentActivity activity) {} @NonNull @MainThread public static ViewModelProvider of(@NonNull Fragment fragment, @NonNull Factory factory) {} @NonNull @MainThread public static ViewModelProvider of(@NonNull FragmentActivity activity, @NonNull Factory factory) {} Fragment͔FragmentActivityͷΈαϙʔτ͍ͯ͠Δ
  47. val user = ViewModelProviders.of(<FragmentActivity || Fragment>) .get(<T : ViewModel>::class.java) val

    user = ViewModelProviders.of(this) .get(UserViewModel::class.java) ViewModelProvider /s ViewModelProvider.get()ʹ͸ ViewModelΛܧঝͨ͠ΫϥεΛࢦఆ͢Δ
  48. ViewModelProvider /s class MyDogFragment : Fragment() { override fun onCreate(savedInstanceState:

    Bundle?) { super.onCreate(savedInstanceState) val userA = ViewModelProviders.of(this).get(UserViewModel::class.java) val userB = ViewModelProviders.of(activity!!).get(UserViewModel::class.java) } } userAͱuserB͸Πϯελϯε͕ҧ͍ ViewModelProviders.of()ʹ౉ͨ͠ΫϥεʹΑͬͯΠϯελϯε͕ܾ·Δ
  49. ViewModelProvider.Factory

  50. ViewModelProvider.Factory val user = ViewModelProviders.of(this).get(UserViewModel::class.java) ViewModelProviders.of()ʹ͸ୈೋҾ਺͕ࢦఆͰ͖ͯ ViewModelͷੜ੒ํ๏ΛมߋͰ͖Δ

  51. ViewModelProvider.Factory val user = ViewModelProviders.of(this).get(UserViewModel::class.java)

  52. val user = ViewModelProviders.of(this, object : ViewModelProvider.Factory { override fun

    <T : ViewModel?> create(modelClass: Class<T>): T { // Կ͔͠Βॲཧ @Suppress("UNCHECKED_CAST") return UserViewModel(repo) as T } }).get(UserViewModel::class.java) ViewModelProvider.Factoryͷࢦఆ
  53. ViewModelProvider.Factoryͷܧঝ class UserViewModelFactory @Inject constructor(val repo: UserRepository) : ViewModelProvider.Factory {

    @Suppress("UNCHECKED_CAST") override fun <T : ViewModel?> create(modelClass: Class<T>): T { return UserViewModel(repo) as T } } ViewModelProvider.FactoryΛܧঝͯ͠Ҿ਺Λ༩͑ͨΓ΋Ͱ͖Δ Dagger౳ͰɺFactoryʹ@Singleton͚ͭͯ؅ཧͨ͠Γ ViewModel΋Injectͨ͠Γ͢Δ৔߹͸ɺ͜ͷܧঝ͕ඞཁʹͳΓ·͢ https://github.com/googlesamples/android-architecture-components/blob/master/GithubBrowserSample/app/src/main/java/com/android/example/github/viewmodel/GithubViewModelFactory.java
  54. ViewModelProvider.Factoryؔ࿈ /** * Simple factory, which calls empty constructor on

    the give class. */ public static class NewInstanceFactory implements Factory {} /** * {@link Factory} which may create {@link AndroidViewModel} and * {@link ViewModel}, which have an empty constructor. */ public static class AndroidViewModelFactory extends ViewModelProvider.NewInstanceFactory {} ͦͷଞ
  55. ՝୊ http://bit.ly/AAC-VM

  56. ՝୊ 0 http://bit.ly/AAC-VM

  57. ՝୊ 0 • Empty Activity Ͱ৽͍͠KotlinϓϩδΣΫτΛ࡞Δ ʢύοέʔδ໊͸ com.sample.viewmodel Λ૝ఆʣ //

    build.gradle apply plugin: 'kotlin-kapt' dependencies { implementation "com.android.support:appcompat-v7:27.0.2" // … implementation "android.arch.lifecycle:extensions:1.1.0" kapt "android.arch.lifecycle:compiler:1.1.0" } http://bit.ly/AAC-VM
  58. ՝୊ 1 http://bit.ly/AAC-VM

  59. ՝୊ 1 • ViewModelΛܧঝͨ͠UserViewModelʹॻ͖׵͑ͯΈΑ͏ class UserViewModel { private var user:

    User? = null fun getUser(): User? { if (user == null) { load() } return user } private fun load() { user = User("Hanyu", 23) } } data class User(val name: String, val age: Int) http://bit.ly/AAC-VM
  60. ՝୊ 1 (ྫ) class UserViewModel : ViewModel() { private var

    user: MutableLiveData<User>? = null fun getUser(): MutableLiveData<User>? { if (user == null) { user = MutableLiveData() load() } return user } private fun load() { user?.postValue(User("Hanyu", 23)) } } data class User(val name: String, val age: Int) http://bit.ly/AAC-VM
  61. ՝୊ 1 - 2 • ܧঝͨ͠UserViewModelΛActivity಺Ͱ࢖ͬͯΈΑ͏ class MainActivity : AppCompatActivity()

    { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) val user = UserViewModel() Log.d("OLYMPICS", user.getUser()?.toString()) } } http://bit.ly/AAC-VM
  62. ՝୊ 1 - 2 (ྫ) class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) val user = ViewModelProviders.of(this).get(UserViewModel::class.java) user.getUser()?.observe(this, Observer { Log.d(“OLYMPICS", it?.toString()) }) } } http://bit.ly/AAC-VM
  63. ՝୊ 1 - 3 • ը໘ճసͯ͠΋ಉ͡Πϯελϯε͔Ͳ͏͔֬ೝͯ͠ΈΑ͏ コレで回転 http://bit.ly/AAC-VM

  64. ՝୊ 2 http://bit.ly/AAC-VM

  65. ՝୊ 2 • Fragment ಺Ͱ userA/B/C ͕ಉ͔֬͡ೝ͠Α͏ class DogFragment :

    Fragment() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val userA = ViewModelProviders.of(this).get(UserViewModel::class.java) val userB = ViewModelProviders.of(activity!!).get(UserViewModel::class.java) val userC = ViewModelProviders.of(this).get(UserViewModel::class.java) } } http://bit.ly/AAC-VM
  66. ՝୊ 3 http://bit.ly/AAC-VM

  67. ՝୊ 3 • 2ͭͷFragment ಺Ͱ user ͕ಉ͔֬͡ೝ͠Α͏ class TopFragment :

    Fragment() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val user = ViewModelProviders.of(this).get(UserViewModel::class.java) } } class BottomFragment : Fragment() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val user = ViewModelProviders.of(this).get(UserViewModel::class.java) } } http://bit.ly/AAC-VM
  68. ViewModelProvider /s ෮श class MyDogFragment : Fragment() { override fun

    onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val userA = ViewModelProviders.of(this).get(UserViewModel::class.java) val userB = ViewModelProviders.of(activity!!).get(UserViewModel::class.java) } } userAͱuserB͸Πϯελϯε͕ҧ͍ ViewModelProviders.of()ʹ౉ͨ͠ΫϥεʹΑͬͯΠϯελϯε͕ܾ·Δ
  69. Thanks. twitter.com/wasabeef_jp wasabeef.jp github.com/wasabeef