GDG Tokyo Android Architecture Components - LiveData

GDG Tokyo Android Architecture Components - LiveData

GDG Tokyo Techtalk Android Architecture Components - LiveData on Jan 24, 2018.

563fab68d455c8543d319436db4819b0?s=128

Takashi EGAWA

January 24, 2018
Tweet

Transcript

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

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

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

    • ୈ3ճ:ViewModel • ୈ4ճ:Room λΠϜςʔϒϧ 19:30ʙ19:35 ѫࡰˍઆ໌ 19:35ʙ20:15 LiveData ͷઆ໌ 20:15ʙ20:25 ٳܜ 20:25ʙ22:00 ՝୊औΓ૊Έ
  4. Download Android Studio 3.1 Canary 8 https://developer.android.com/studio/preview/index.html?hl=ja

  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 ࠓ೔ͷςʔϚ͸͜Ε લճ ࣍ճ
  9. LiveData

  10. LiveData • observe (؂ࢹ) Մೳͳσʔλ • Activity/Fragment/Service ͳͲͷϥΠϑαΠΫϧΛҙࣝ (Lifecyclesͷ࢓૊ΈΛར༻ʣ •

    Ұൠతʹ͸ ViewModel ͱ࿈ܞͯ͠ར༻͢Δ (ViewModelͱViewͷؒͷކͷΑ͏ͳ໾໨ΛՌͨ͢ʣ
  11. Lifecycles ͓͞Β͍

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

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

    • STARTED • RESUMED https://developer.android.com/topic/libraries/architecture/lifecycle.html
  14. 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
  15. FragmentActivity ͔Β Lifecycle Λऔಘ͢Δ public class MainActivity extends AppCompatActivity {

    @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); final Lifecycle lifecycle = getLifecycle(); }
  16. ݱࡏͷϥΠϑαΠΫϧΛऔಘ͢Δ final Lifecycle.State state = lifecycle.getCurrentState();

  17. ϥΠϑαΠΫϧΛ؂ࢹ͢Δ lifecycle.addObserver(observer);

  18. LiveData

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

    LiveData • MediatorLiveData (android.arch.lifecycle) ෳ਺ͷ LiveData ΛଋͶͯ؅ཧ͢Δ LiveData * Java8 Language Support * RxJava * ReactiveStreams ʹ͍ͭͯ͸ࠓճ͸औΓ্͛·ͤΜ
  20. android.arch.lifecycle.LiveData<T> observe(@NonNull LifecycleOwner owner, @NonNull Observer<T> observer) ͜ͷLiveDataͷ஋Λ؂ࢹ͢Δ ༩͑ΒΕͨLifeCycleOwnerͷϥΠϑαΠΫϧ ʹैͬͯɺobserverʹ௨஌͞ΕΔ

    observerʹ௨஌͞ΕΔͷ͸ϥΠϑαΠΫϧ͕ ΞΫςΟϒͷͱ͖ͷΈ active
  21. android.arch.lifecycle.LiveData<T> observeForever(@NonNull Observer<T> observer) ϥΠϑϥΠΫϧͷΞΫςΟϒঢ়ଶʹ͔͔ΘΒͣ௨஌Λड͚औΔ CREATED ͷঢ়ଶͰ΋௨஌Λड͚औΕΔ

  22. android.arch.lifecycle.LiveData<T> onActive() ΞΫςΟϒঢ়ଶʹ͋ΔΦϒβʔόʔ͕1Ҏ্ʹͳͬͨࡍʹݺ͹ΕΔ onInactive() ΞΫςΟϒঢ়ଶʹ͋ΔΦϒβʔόʔ͕1ະຬʹͳͬͨࡍʹݺ͹ΕΔ getValue() ݱࡏͷ஋Λฦ͢

  23. android.arch.lifecycle.Observer<T> onChanged(@Nullable T t) ஋͕มߋ͞Εͨࡍʹݺ͹ΕΔ LiveData ͔Βͷ஋Λड͚औΔγϯϓϧͳΠϯλϑΣʔε

  24. android.arch.lifecycle.MutableLiveData<T> ௨ৗͷ LiveData ͸֎෦͔Β஋ΛઃఆͰ͖ͳ͍ MutableLiveData ͸֎෦͔Β஋ΛઃఆՄೳͳϝιουΛެ։͍ͯ͠Δ

  25. android.arch.lifecycle.MutableLiveData<T> setValue(T value) ஋Λઃఆ͢ΔʢϝΠϯεϨουͰݺͼग़͢͜ͱʣ postValue(T value) ϝΠϯεϨου֎͔Β஋Λઃఆ͢Δࡍͷศརϝιου

  26. android.arch.lifecycle.MediatorLiveData<T> addSource(@NonNull LiveData<S> source, @NonNull Observer<S> onChanged) LiveData Λ௥Ճ͢Δ removeSource(@NonNull

    LiveData<S> toRemote) LiveData Λ࡟আ͢Δ ෳ਺ͷ LiveData ΛଋͶͯ؅ཧͰ͖ΔΫϥε ܕͷҧ͏ෳ਺ͷLiveDataʹΠϕϯτΛ఻೻ͤ͞Δ͜ͱ͕Ͱ͖Δ
  27. android.arch.lifecycle.Transformations static <X, Y> LiveData<Y> map(@NonNull LiveData<X> source, @NonNull final

    Function<X, Y> func) LiveData ʹରͯؔ͠਺(func)Λద༻͠ɺผͷ LiveData ʹΠϕϯτΛ఻೻ͤ͞Δ static <X, Y> LiveData<Y> switchMap(@NonNull LiveData<X> trigger, @NonNull final Function<X, LiveData<Y>> func) mapͱྨࣅͨ͠ϝιου͕ͩؔ਺(func)಺͔Β LiveData Λฦ͢͜ͱ͕Ͱ͖Δ MediatorLiveData Λ࢖͍΍ͨ͘͢͠ϢʔςΟϦςΟ Java͔Β࢖͏ͱͱͯ΋μα͘ͳΔʂKotlinਪ঑
  28. ՝୊

  29. ՝୊ 0 • Empty Activity Ͱ৽͍͠ϓϩδΣΫτΛ࡞Δ ʢύοέʔδ໊͸ com.example.livedatacodelab Λ૝ఆʣ •

    build.grade dependencies { implementation “com.android.support:appcompat-v7:27.0.2” … implementation "android.arch.lifecycle:extensions:1.1.0" annotationProcessor "android.arch.lifecycle:compiler:1.1.0" } • MainActivity ͷ onCreate ͷதͰ LifecycleObserver Λ࢖ͬͯɺϥΠϑαΠΫϧ มߋ࣌ʹݱࡏͷϥΠϑαΠΫϧͷঢ়ଶΛϩάʹग़ྗ͢ΔΑ͏ʹ͢Δ • Ͱ͖ͨΒɺը໘Λดͨ͡Γɺ։͍ͨΓɺཪʹճͨ͠Γɺը໘Λճసͤͨ͞Γͯ͠ϥΠϑα ΠΫϧͷঢ়ଶ͕ͲͷΑ͏ʹมΘΔ͔Λ֬ೝ͢Δ
  30. public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle

    savedInstanceState) { super.onCreate(savedInstanceState); … final LifecycleObserver lifecycleObserver = new LifecycleObserver() { @OnLifecycleEvent(Lifecycle.Event.ON_ANY) public void calledWhenOnAny(LifecycleOwner source, Lifecycle.Event event) { Log.d("CODELAB", "Lifecycle state:" + source.getLifecycle().getCurrentState().name()); } }; getLifecycle().addObserver(lifecycleObserver); } } ྫ https://gist.github.com/egglang/f9014730def32395daae657429a08f1b
  31. ՝୊ 1 • ݱࡏ࣌ࠁͷ࣌෼ HH:MM Λը໘ʹදࣔ͢Δ࣌ܭΞϓϦΛ࡞Δ ʢϩέʔϧͳͲͷࡉ͔͍͜ͱ͸ؾʹ͠ͳ͍Ͱʣ activity_main.xml ͷ TextView

    ʹద౰ͳ id Λ͚ͭͯɺͦ͜ʹग़͢ • ·ͣ͸ɺݹ͍ํ๏Ͱ΍ͬͯΈΔ • Ұྫͱͯ͠ɺ࣍ͷϖʔδʹ ClockLegacy ΫϥεΛهࡌ͍ͯ͠·͢ɻ • ͜ͷΫϥεΛίϐϖͯ͠ MainActivity ͔Β࢖ͬͯԼ͍͞ • ࣗ෼Ͱ΍Γ͍ͨਓ͸͜ΕΛ࢖Θͣʹ޷͖ʹ࣮૷ͯ͘͠Εͯ΋͍͍Ͱ͢ɻ
  32. import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import java.util.Calendar;

    import java.util.Date; public class ClockLegacy { private final Context mAppContext; public interface ClockListener { void onReceive(Date date); } private ClockListener mListener; private BroadcastReceiver mTimeTickBroadcastReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { if (mListener != null) { mListener.onReceive(Calendar.getInstance().getTime()); } } }; public ClockLegacy(Context appContext) { mAppContext = appContext; } public void setClockListener(ClockListener listener) { if (mListener != null) { return; } mListener = listener; IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(Intent.ACTION_TIME_TICK); mAppContext.registerReceiver(mTimeTickBroadcastReceiver, intentFilter); } public void removeClockListener() { mListener = null; mAppContext.unregisterReceiver(mTimeTickBroadcastReceiver); } } https://gist.github.com/egglang/ae119ac753b901bbd2301dc323fd7402
  33. private TextView mText; private ClockLegacy.ClockListener mListener = new ClockLegacy.ClockListener() {

    @Override public void onReceive(Date date) { Calendar cal = Calendar.getInstance(); cal.setTime(date); String dateString = String.format("%02d:%02d", cal.get(Calendar.HOUR_OF_DAY), cal.get(Calendar.MINUTE)); mText.setText(dateString); Log.d("CODELAB", “The current time is " + dateString); } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); .. mText = findViewById(R.id.text); mClockData = new ClockLegacy(getApplicationContext()); final LifecycleObserver observer = new LifecycleObserver() { @OnLifecycleEvent(Lifecycle.Event.ON_START) public void calledWhenOnStart(LifecycleOwner source) { mClockData.setClockListener(mListener); } @OnLifecycleEvent(Lifecycle.Event.ON_STOP) public void calledWhenOnStop(LifecycleOwner source) { mClockData.removeClockListener(); } }; getLifecycle().addObserver(observer); } ClockLegacy Λ࢖ͬͨ MainActivity ͷ࣮૷ྫ https://gist.github.com/egglang/8862bc8ed7131dc5b847dcd5680a2d4e
  34. ՝୊ 2 • ݹ͍ํ๏ ClockLegacy Ϋϥεͷ࣮૷Λ LiveData Ͱॻ͖׵͑ͯΈΔ • ClockLiveData

    ΫϥεΛ࡞੒͢Δʢ࣍ͷϖʔδʹςϯϓϨ public class ClockLiveData extends LiveData<Date> { ... } • MainActivity ͷ onCreate ͷதͰ ClockLiveData ʹ observe ͢Δ ʢClockLegacy Λ࢖͏ͷ͸ࢭΊΔʣ
  35. import android.arch.lifecycle.LiveData; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter;

    import android.util.Log; import java.util.Calendar; import java.util.Date; public class ClockLiveData extends LiveData<Date> { private final Context mAppContext; private BroadcastReceiver mTimeTickBroadcastReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { // ... } }; public ClockLiveData(Context appContext) { mAppContext = appContext; } @Override protected void onActive() { IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(Intent.ACTION_TIME_TICK); mAppContext.registerReceiver(mTimeTickBroadcastReceiver, intentFilter); } @Override protected void onInactive() { mAppContext.unregisterReceiver(mTimeTickBroadcastReceiver); } } https://gist.github.com/egglang/319231352e5538bfb9641634480aee04
  36. ՝୊ 2 ͷ 2 • ClockLiveDataͷonActive, onInactive ʹϩάΛૠೖ͠ɺ͍ͭݺ͹Εͯ ͍Δ͔֬ೝ͠·͠ΐ͏ •

    HomeϘλϯΛԡͯ͠Recent Apps͔Β෮ؼͨ͠ͱ͖ʹɺ࣌෼ͷදࣔ͸Ͳ͏ͳ Δʁ • ͙͢ʹ෮ؼͤͨ͞৔߹͸ʁ਺෼଴͔ͬͯΒ෮ؼͤͨ͞৔߹͸ʁ • observe ϝιουͷ୅ΘΓʹ observeForever ϝιουΛ࢖ͬͨΒʁ • ը໘Λճసͤͨ͞ͱ͖͸ʁ • MainActivity ͔Β ClockLiveData ʹ௚઀ setValue ͠Α͏ͱͨ͠Βʁ
  37. ՝୊ 3 • ؆୯ͳ ViewModel Λͪΐͬͱ͚ͩ࢖ͬͯΈ·͠ΐ͏ • ClockLiveData ͷ਌Λ MutableLiveData

    ʹม͑ΔʢViewModel͔ΒΞΫηεͰ͖ΔΑ͏ʹʣ public class ClockLiveData extends MutableLiveData<Date> • ClockViewModel ΫϥεΛ৽ͨʹ࡞Δ public class ClockViewModel extends AndroidViewModel { private MutableLiveData<Date> clock; public ClockViewModel(@NonNull Application application) { super(application); } public LiveData<Date> getClock() { if (clock == null) { clock = new ClockLiveData(getApplication()); } return clock; } } • MainActivity ͷ onCreate Ͱ ViewModel Λऔಘ͠ɺgetClock Ͱ observer Λઃఆ͢Δ ClockViewModel clockViewModel = ViewModelProviders.of(this).get(ClockViewModel.class); clockViewModel.getClock().observe(...); • Ͱ͖ͨΒɺը໘Λճసͤͨ͞ͱ͖ʹ࣌෼ͷද͕ࣔͲ͏ͳΔ͔༡ΜͰΈͯԼ͍͞ ViewModelͷৄࡉ͸ ࣍ճʹ΍Γ·͢ͷͰ ਂ͘ߟ͑ͳ͍ͰԼ͍͞ https://gist.github.com/egglang/221a0dcb016d80766cabee91fe42d476
  38. ՝୊ 4 • σʔλόΠϯσΟϯάΛ࢖ͬͯ LiveDataͱ TextView Λܨ͛ͯΈ·͠ΐ͏ • build.gradle android

    { compileSdkVersion 27 dataBinding { enabled = true } ... • ClockLiveData ͸Ұ੾มߋ͠ͳ͍ͰɺܕҾ਺΋ Date ͷ··ͰʢStringʹ͠ͳ͍Ͱʣ΍ͬͯΈ·͠ΐ͏ • ҎԼͷ˚ͷΑ͏ͳํ๏΋͋ΓͰ͕͢ࠓճ͸ͳΔ΂͘ແ͠Ͱ Transformations ͰLiveDataΛม׵ͯ͠Լ͞ ͍ △ <TextView android:text="@{DateFormatUtils.format(hoge, `HH:mm`)}" /> ◦ <TextView android:text=“@{foo.bar)}" /> ࢀߟɿσʔλόΠϯσΟϯά https://developer.android.com/topic/libraries/data-binding/index.html?hl=ja
  39. <?xml version="1.0" encoding="utf-8"?> <layout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"> <data> <variable name="clockModel" type="com.example.livedatacodelab.ClockViewModel"/>

    </data> <android.support.constraint.ConstraintLayout android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{clockModel.clock}" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent"/> </android.support.constraint.ConstraintLayout> </layout> ώϯτ: activity_main.xml ͷྫ https://gist.github.com/egglang/95fbd6d5748f54960030e51d07eab1e4
  40. package com.example.livedatacodelab; import android.arch.lifecycle.ViewModelProviders; import android.databinding.DataBindingUtil; import android.os.Bundle; import android.support.v7.app.AppCompatActivity;

    import com.example.livedatacodelab.databinding.ActivityMainBinding; public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ClockViewModel clockViewModel = ViewModelProviders.of(this).get(ClockViewModel.class); ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main); binding.setLifecycleOwner(this); binding.setClockModel(clockViewModel); } } ώϯτ: MainActivity ͷྫ https://gist.github.com/egglang/e7aef650555b932298d6a0c21917c889
  41. EOF