Android Architecture ComponentのLifecyle対応コンポーネントのおさらい / Review of Lifecyle aware components of AAC

Android Architecture ComponentのLifecyle対応コンポーネントのおさらい / Review of Lifecyle aware components of AAC

Ce6acc3536b0e0340b5f0569d3394c9c?s=128

Yasutaka Kawamoto

January 25, 2020
Tweet

Transcript

  1. 2.

    • Տຊ ହ޹(͔Θ΋ͱ ΍͔ͨ͢) • ॴଐɿגࣜձࣾ tech vein 
 (େࡕࢢதԝ۠ຊொ)

    • ϞόΠϧΞϓϦΤϯδχΞ
 (AndroidଟΊɺiOS΋ŧŔŕŪũƄŝſ) • GitHub: kwmt ɺtwitter: kwmt27 • Google I/O2018 ॳࢀՃ • ෱Ԭग़਎ • ΫϥϑτϏʔϧ޷͖ ࣗݾ঺հ
  2. 17.

    ViewModelͷੜଘظؒ onCreate ࣌ؒ ViewModelੜ੒ onStart onResume onPause onStop onDestroy onCreate

    onStart onResume ىಈ ճస όοΫΩʔͰΞϓϦऴྃ Activity ViewModel
  3. 18.

    ViewModelͷੜଘظؒ onCreate ࣌ؒ ViewModelੜ੒ onStart onResume onPause onStop onDestroy onCreate

    onStart onResume onPause onStop onDestroy ىಈ ճస όοΫΩʔͰΞϓϦऴྃ onCleared Activity ViewModel
  4. 19.

    ViewModelͷੜଘظؒ onCreate ࣌ؒ ViewModelੜ੒ onStart onResume onPause onStop onDestroy onCreate

    onStart onResume onPause onStop onDestroy ىಈ ճస όοΫΩʔͰΞϓϦऴྃ onCleared Activity ViewModel
  5. 20.

    override fun onCreate(savedInstanceState: Bundle?) { // লུ val chronometer =

    findViewById(R.id.chronometer) val startTime = viewModel.startTime if (startTime == null) { val time = SystemClock.elapsedRealtime() viewModel.startTime = time chronometer.base = time } else { chronometer.base = startTime } chronometer.start() } Activity class ChronoViewModel: ViewModel() { var startTime: Long? = null } ViewModel
  6. 22.

    • Kotlin ϓϩύςΟσϦήʔτΛ࢖͏ํ๏ ViewModelΠϯελϯεͷऔಘํ๏ (஫ҙ)fragment-ktxͷ1.1.0Ҏ্Λ࢖͏ඞཁ͋Γ val viewModel by viewModels<MyViewModel>() https://developer.android.com/jetpack/androidx/releases/lifecycle#2.2.0-alpha03

    ViewModelProviders.of(this) .get(MyViewModel::class.java) • ViewModelProviderΛ࢖͏ํ๏ viewModel = ViewModelProvider(this) .get(MyViewModel::class.java) 2.2.0-alpha03͔ΒDeprecated
  7. 27.

    ViewModelʹߋ৽͍ͨ͠ViewΛ ࣋ͨͤͨΒ͍͍Μ͡Όʁ class MyViewModel : ViewModel() { val initialTime =

    SystemClock.elapsedRealtime() private val timer = Timer() var timerTextView: TextView? = null init{ timer.scheduleAtFixedRate(object : TimerTask() { override fun run() { timerTextView?.text = "$ඵ਺ ඵܦա" } }, 1000, 1000) } }
  8. 28.

    ViewModelʹߋ৽͍ͨ͠ViewΛ ࣋ͨͤͨΒ͍͍Μ͡Όʁ class MyViewModel : ViewModel() { val initialTime =

    SystemClock.elapsedRealtime() private val timer = Timer() var timerTextView: TextView? = null init{ timer.scheduleAtFixedRate(object : TimerTask() { override fun run() { timerTextView?.text = "$ඵ਺ ඵܦա" } }, 1000, 1000) } } • ΞϓϦऴྃ࣌ʹϝϞϦϦʔΫ͢ΔͷͰɺͰ͖·ͤΜɻ
  9. 29.

    ViewModelʹߋ৽͍ͨ͠ViewΛ ࣋ͨͤͨΒ͍͍Μ͡Όʁ class MyViewModel : ViewModel() { val initialTime =

    SystemClock.elapsedRealtime() private val timer = Timer() var timerTextView: TextView? = null init{ timer.scheduleAtFixedRate(object : TimerTask() { override fun run() { timerTextView?.text = "$ඵ਺ ඵܦա" } }, 1000, 1000) } } • ΞϓϦऴྃ࣌ʹϝϞϦϦʔΫ͢ΔͷͰɺͰ͖·ͤΜɻ AACͷLiveDataΛ࢖͍·͢ʂ
  10. 30.

    LiveDataΛ࢖͏ class MyViewModel : ViewModel() { val initialTime = SystemClock.elapsedRealtime()

    private val timer = Timer() private val elapsedTime = MutableLiveData<Long>() fun getElapsedTime(): LiveData<Long> = elapsedTime init{ timer.scheduleAtFixedRate(object : TimerTask() { override fun run() { elapsedTime.postValue(ඵ਺) } }, 1000, 1000) } } viewModel.getElapsedTime()
 .observe(this, Observer { timerTextView.text = "${t}ඵܦա" }) • Activityଆ
  11. 31.

    LiveDataΛ࢖͏ class MyViewModel : ViewModel() { val initialTime = SystemClock.elapsedRealtime()

    private val timer = Timer() private val elapsedTime = MutableLiveData<Long>() fun getElapsedTime(): LiveData<Long> = elapsedTime init{ timer.scheduleAtFixedRate(object : TimerTask() { override fun run() { elapsedTime.postValue(ඵ਺) } }, 1000, 1000) } } viewModel.getElapsedTime()
 .observe(this, Observer { timerTextView.text = "${t}ඵܦա" }) • Activityଆ
  12. 39.

    ͜͜Ͱղܾ͍ͨ͠՝୊ Activity override fun onResume(){ locationManager.requestLocationUpdates(লུ) } override fun onPause(){

    locationManager.removeUpdates(লུ) } • AndroidͷϥΠϒϥϦ΍API͸͜ͷΑ͏ͳॲཧΛ͢Δ΋ͷ ͕ଟ͍ͷͰɺActivity΍FragmentΫϥε͕๲ΒΜͰ͖ͯɺ ಡΈʹ͘͘ͳΓ·͢ɻ
  13. 40.

    Activity override fun onCreate(){ LocationLifecyle(this) } Lifecycle class LocationLifecycle(lifecycleOwner: LifecycleOwner)

    ɹɹɹ: LifecycleObserver { init { lifecycleOwner.lifecycle.addObserver(this) } @OnLifecycleEvent(ON_RESUME) fun addLocationListener() { locationManager.requestLocationUpdates(লུ) } @OnLifecycleEvent(ON_PAUSE) fun removeLocationListener() { locationManager.removeUpdates(লུ) } }
  14. 41.

    Activity override fun onCreate(){ LocationLifecyle(this) } Lifecycle class LocationLifecycle(lifecycleOwner: LifecycleOwner)

    ɹɹɹ: LifecycleObserver { init { lifecycleOwner.lifecycle.addObserver(this) } @OnLifecycleEvent(ON_RESUME) fun addLocationListener() { locationManager.requestLocationUpdates(লུ) } @OnLifecycleEvent(ON_PAUSE) fun removeLocationListener() { locationManager.removeUpdates(লུ) } } interfaceΛ࣮૷
  15. 42.

    Activity override fun onCreate(){ LocationLifecyle(this) } Lifecycle class LocationLifecycle(lifecycleOwner: LifecycleOwner)

    ɹɹɹ: LifecycleObserver { init { lifecycleOwner.lifecycle.addObserver(this) } @OnLifecycleEvent(ON_RESUME) fun addLocationListener() { locationManager.requestLocationUpdates(লུ) } @OnLifecycleEvent(ON_PAUSE) fun removeLocationListener() { locationManager.removeUpdates(লུ) } } interfaceΛ࣮૷ observerΛొ࿥
  16. 43.

    Activity override fun onCreate(){ LocationLifecyle(this) } Lifecycle class LocationLifecycle(lifecycleOwner: LifecycleOwner)

    ɹɹɹ: LifecycleObserver { init { lifecycleOwner.lifecycle.addObserver(this) } @OnLifecycleEvent(ON_RESUME) fun addLocationListener() { locationManager.requestLocationUpdates(লུ) } @OnLifecycleEvent(ON_PAUSE) fun removeLocationListener() { locationManager.removeUpdates(লུ) } } interfaceΛ࣮૷ observerΛొ࿥ ϥΠϑαΠΫϧʹґ ଘ͍ͨ͠ϝιουʹ ΞϊςʔγϣϯΛͭ ͚Δ
  17. 47.

    class FugaFragment : Fragment() { interface OnClickListener { fun onClick()

    } private var onClickListener: OnClickListener? = null // লུ override fun onActivityCreated { // লུ onClickListener = requireActivity() as? OnClickListener // ϘλϯͳͲͷΫϦοΫΠϕϯτͰonClickΛݺͿ onClickListener?.onClick() } } class HogeActivity : AppCompatActivity(), FugaFragment.OnClickListener { // লུ override fun onClick() { // ͳʹ͔ } }
  18. 48.

    class FugaFragment : Fragment() { interface OnClickListener { fun onClick()

    } private var onClickListener: OnClickListener? = null // লུ override fun onActivityCreated { // লུ onClickListener = requireActivity() as? OnClickListener // ϘλϯͳͲͷΫϦοΫΠϕϯτͰonClickΛݺͿ onClickListener?.onClick() } } class HogeActivity : AppCompatActivity(), FugaFragment.OnClickListener { // লུ override fun onClick() { // ͳʹ͔ } } ௨஌༻interfaceΛఆٛ ϑΟʔϧυʹม਺༻ҙ Activity͕interfaceΛ࣮૷ͯͨ͠ΒΩϟετ ௨஌༻ͷinterfaceΛ࣮૷
  19. 50.

    class HogeActivity : AppCompatActivity() { private val viewModel by viewModels<HogeViewModel>()

    override fun onCreate(savedInstanceState: Bundle?) { // লུ viewModel.clickEvent.observe(this) { textView.text = it } } } private val viewModel by viewModels<HogeViewModel> ({ requireActivity() }) viewModel.onClick() class HogeViewModel : ViewModel() { val clickEvent = MutableLiveData<String>() fun onClick() { clickEvent.value = "Ϙλϯ͕ԡ͞ΕͨΑ" } }
  20. 55.
  21. 59.

    MediatorLiveDataΛ࢖͏ class ZipLIveDataViewModel : ViewModel() { val editText1 = MutableLiveData<String>()

    val editText2 = MutableLiveData<String>() val isEnabled = MediatorLiveData<Boolean>() init { val observer = Observer<String> { isEnabled.value = editText1.value?.isNotEmpty() ?: false && editText2.value?.isNotEmpty() ?: false } isEnabled.addSource(editText1, observer) isEnabled.addSource(editText2, observer) } }
  22. 60.

    MediatorLiveDataͷϥούʔؔ਺Λ࡞Δ fun <A, B> zipLiveData(a: LiveData<A>, b: LiveData<B>): LiveData<Pair<A, B>>

    { return MediatorLiveData<Pair<A, B>>().apply { var lastA: A? = null var lastB: B? = null fun update() { val localLastA = lastA val localLastB = lastB if (localLastA != null && localLastB != null) { this.value = Pair(localLastA, localLastB) } } addSource(a) { lastA = it update() } addSource(b) { lastB = it update() } } } https://medium.com/@gauravgyal/combine-results-from-multiple-async-requests-90b6b45978f7
  23. 61.

    MediatorLiveDataͷϥούʔؔ਺Λ࢖͏ class ZipLIveDataViewModel : ViewModel() { val editText1 = MutableLiveData<String>()

    val editText2 = MutableLiveData<String>() val isEnabled: LiveData<Boolean> = zipLiveData(editText1, editText2) .map { (t1, t2) -> t1.isNotEmpty() && t2.isNotEmpty() } }
  24. 62.

    ൺ΂Δ class ZipLIveDataViewModel : ViewModel() { val editText1 = MutableLiveData<String>()

    val editText2 = MutableLiveData<String>() val isEnabled: LiveData<Boolean> = zipLiveData(editText1, editText2) .map { (t1, t2) -> t1.isNotEmpty() && t2.isNotEmpty() } } class ZipLIveDataViewModel : ViewModel() { val editText1 = MutableLiveData<String>() val editText2 = MutableLiveData<String>() val isEnabled = MediatorLiveData<Boolean>() init { val observer = Observer<String> { isEnabled.value = editText1.value?.isNotEmpty() ?: false && editText2.value?.isNotEmpty() ?: false } isEnabled.addSource(editText1, observer) isEnabled.addSource(editText2, observer) } }
  25. 63.
  26. 64.
  27. 67.

    ભҠݩʹ໭Εͳ͍࣮૷ྫ override fun onViewCreated() { viewModel.nextLiveData .observe(viewLifecycleOwner) { nextViewType ->

    // ը໘ભҠ͢Δ } button .setOnClickListener{viewModel.onClickNextButton()}
 } fun onClickNextButton() { // APIϨεϙϯεͷ݁ՌʹΑͬͯɺը໘ભҠΛม͍͑ͨ৔߹ val data = repository.fetchData() // লུ _nextLiveData.value = nextType } Fragment ViewModel
  28. 68.

    ભҠݩʹ໭Εͳ͍࣮૷ྫ override fun onViewCreated() { viewModel.nextLiveData .observe(viewLifecycleOwner) { nextViewType ->

    // ը໘ભҠ͢Δ } button .setOnClickListener{viewModel.onClickNextButton()}
 } fun onClickNextButton() { // APIϨεϙϯεͷ݁ՌʹΑͬͯɺը໘ભҠΛม͍͑ͨ৔߹ val data = repository.fetchData() // লུ _nextLiveData.value = nextType } Fragment ViewModel όοΫͰ໭͖ͬͯͨͱ͖ʹɺ onViewCreated͕ݺ͹Εͯɺ observe͍ͯ͠ΔonChanged͕ݺ͹ΕΔͨΊ
  29. 69.

    LiveDataͷϥούʔΫϥεΛ࡞Δ https://medium.com/androiddevelopers/livedata-with-snackbar-navigation-and-other-events-the-singleliveevent-case-ac2622673150 data class Event<out T>(private val content: T) {

    var hasBeenHandled = false private set fun getContentIfNotHandled(): T? { return if (hasBeenHandled) { null } else { hasBeenHandled = true content } } }
  30. 70.

    LiveDataͷϥούʔΫϥε(Event)Λ࢖͏ override fun onViewCreated() { viewModel.nextLiveData .observe(viewLifecycleOwner) { event ->

    event.getContentIfNotHandled()?.let {nextViewType -> // ը໘ભҠ͢Δ
 } } button .setOnClickListener{viewModel.onClickNextButton()}
 } fun onClickNextButton() { // APIϨεϙϯεͷ݁ՌʹΑͬͯɺը໘ભҠΛม͍͑ͨ৔߹ val data = repository.fetchData() // লུ _nextLiveData.value = Event(nextType) } Fragment ViewModel
  31. 71.

    LiveDataͷϥούʔΫϥε(Event)Λ࢖͏ override fun onViewCreated() { viewModel.nextLiveData .observe(viewLifecycleOwner) { event ->

    event.getContentIfNotHandled()?.let {nextViewType -> // ը໘ભҠ͢Δ
 } } button .setOnClickListener{viewModel.onClickNextButton()}
 } fun onClickNextButton() { // APIϨεϙϯεͷ݁ՌʹΑͬͯɺը໘ભҠΛม͍͑ͨ৔߹ val data = repository.fetchData() // লུ _nextLiveData.value = Event(nextType) } Fragment ViewModel EventΛηοτ͢ΔΑ͏ʹมߋ
  32. 72.

    LiveDataͷϥούʔΫϥε(Event)Λ࢖͏ override fun onViewCreated() { viewModel.nextLiveData .observe(viewLifecycleOwner) { event ->

    event.getContentIfNotHandled()?.let {nextViewType -> // ը໘ભҠ͢Δ
 } } button .setOnClickListener{viewModel.onClickNextButton()}
 } fun onClickNextButton() { // APIϨεϙϯεͷ݁ՌʹΑͬͯɺը໘ભҠΛม͍͑ͨ৔߹ val data = repository.fetchData() // লུ _nextLiveData.value = Event(nextType) } Fragment ViewModel getContentIfNotHandled()ͷ࢓૊ΈͰɺ όοΫͰ໭͖ͬͯͨͱ͖͸null͕ฦΔ ͨΊɺը໘ભҠ͠ͳ͘ͳΓɺ ݩͷը໘ʹ໭Δ͜ͱ͕Ͱ͖Δ EventΛηοτ͢ΔΑ͏ʹมߋ
  33. 73.
  34. 74.