Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
GDG Tokyo Android Architecture Components - Liv...
Search
Takashi EGAWA
January 24, 2018
Programming
9
2.3k
GDG Tokyo Android Architecture Components - LiveData
GDG Tokyo Techtalk Android Architecture Components - LiveData on Jan 24, 2018.
Takashi EGAWA
January 24, 2018
Tweet
Share
More Decks by Takashi EGAWA
See All by Takashi EGAWA
Fuchsia Shibuya.apk #28 2018.9.28
t_egg
1
250
Android TV - Japan Android Group 2016 Aug.
t_egg
0
520
DroidKaigi 2016 パフォーマンスを追求したAndroidアプリを作るには
t_egg
9
8.7k
Other Decks in Programming
See All in Programming
Tauriでネイティブアプリを作りたい
tsucchinoko
0
370
Jakarta EE meets AI
ivargrimstad
0
120
距離関数を極める! / SESSIONS 2024
gam0022
0
290
「今のプロジェクトいろいろ大変なんですよ、app/services とかもあって……」/After Kaigi on Rails 2024 LT Night
junk0612
5
2.2k
Realtime API 入門
riofujimon
0
150
카카오페이는 어떻게 수천만 결제를 처리할까? 우아한 결제 분산락 노하우
kakao
PRO
0
110
Quine, Polyglot, 良いコード
qnighy
4
650
Laravel や Symfony で手っ取り早く OpenAPI のドキュメントを作成する
azuki
2
120
3 Effective Rules for Using Signals in Angular
manfredsteyer
PRO
0
100
Click-free releases & the making of a CLI app
oheyadam
2
120
Micro Frontends Unmasked Opportunities, Challenges, Alternatives
manfredsteyer
PRO
0
110
どうして僕の作ったクラスが手続き型と言われなきゃいけないんですか
akikogoto
1
120
Featured
See All Featured
Distributed Sagas: A Protocol for Coordinating Microservices
caitiem20
329
21k
VelocityConf: Rendering Performance Case Studies
addyosmani
325
24k
実際に使うSQLの書き方 徹底解説 / pgcon21j-tutorial
soudai
169
50k
"I'm Feeling Lucky" - Building Great Search Experiences for Today's Users (#IAC19)
danielanewman
226
22k
Creating an realtime collaboration tool: Agile Flush - .NET Oxford
marcduiker
25
1.8k
Producing Creativity
orderedlist
PRO
341
39k
The Art of Programming - Codeland 2020
erikaheidi
52
13k
The MySQL Ecosystem @ GitHub 2015
samlambert
250
12k
The Pragmatic Product Professional
lauravandoore
31
6.3k
A better future with KSS
kneath
238
17k
Practical Tips for Bootstrapping Information Extraction Pipelines
honnibal
PRO
10
720
BBQ
matthewcrist
85
9.3k
Transcript
Architecture Components ษڧձ ͕͑Θ Θ͞ͼʔ; ͋Β͖ ͋Μ͍͟Ώ͖ ୈ2ճ LiveData
Architecture Componentsษڧձ ͱ • Architecture Componentsͷجૅࣝʹֶ͍ͭͯͿษڧձ • ओ࠵ɿGDG Tokyo ϋογϡλά:
#gdgtokyo • ߨࢣɺνϡʔλʔɿGoogleࣾһͱGoogle Developer Expert ʢ͋Μ͍͟Ώ͖ɺ ͕͑ΘɺΘ͞ͼʔ;ɺ͋Β͖ʣ
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 ՝औΓΈ
Download Android Studio 3.1 Canary 8 https://developer.android.com/studio/preview/index.html?hl=ja
Architecture Components ͱ • ෳͷػೳɾϥΠϒϥϦͷ૯শ • Lifecycles • LiveData •
ViewModel • Room • Paging
Architecture Components ͱ • ෳͷػೳɾϥΠϒϥϦͷ૯শ • Lifecycles • LiveData •
ViewModel • Room • Paging ݸผར༻OK
Architecture Components ͱ • ෳͷػೳɾϥΠϒϥϦͷ૯শ • Lifecycles • LiveData •
ViewModel • Room • Paging ݸผར༻OK Έ߹Θͤར༻OK
Architecture Components ͱ • ෳͷػೳɾϥΠϒϥϦͷ૯শ • Lifecycles • LiveData •
ViewModel • Room • Paging ࠓͷςʔϚ͜Ε લճ ࣍ճ
LiveData
LiveData • observe (ࢹ) Մೳͳσʔλ • Activity/Fragment/Service ͳͲͷϥΠϑαΠΫϧΛҙࣝ (LifecyclesͷΈΛར༻ʣ •
Ұൠతʹ ViewModel ͱ࿈ܞͯ͠ར༻͢Δ (ViewModelͱViewͷؒͷކͷΑ͏ͳΛՌͨ͢ʣ
Lifecycles ͓͞Β͍
Lifecycles • Lifecycles = Lifecycle-aware Components • ϥΠϑαΠΫϧΛݕ͢Δίϯϙʔωϯτ • Activity
Fragment ͷϥΠϑαΠΫϧঢ়ଶ͕มΘͬͨͱ͖ʹԿ͔ ΞΫγϣϯΛى͜͢ɺͱ͍͏͜ͱ͕Ͱ͖ΔΑ͏ʹͳΔ
Lifecycle.State • ݱࡏͷϥΠϑαΠΫϧঢ়ଶΛද͢ enum • INITIALIZED • DESTROYED • CREATED
• STARTED • RESUMED https://developer.android.com/topic/libraries/architecture/lifecycle.html
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
FragmentActivity ͔Β Lifecycle Λऔಘ͢Δ public class MainActivity extends AppCompatActivity {
@Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); final Lifecycle lifecycle = getLifecycle(); }
ݱࡏͷϥΠϑαΠΫϧΛऔಘ͢Δ final Lifecycle.State state = lifecycle.getCurrentState();
ϥΠϑαΠΫϧΛࢹ͢Δ lifecycle.addObserver(observer);
LiveData
ओͳLiveData • LiveData (android.arch.lifecycle) ௨ৗͷ LiveData • MutableLiveData (android.arch.lifecycle) ֎෦͔ΒมߋՄೳͳ
LiveData • MediatorLiveData (android.arch.lifecycle) ෳͷ LiveData ΛଋͶͯཧ͢Δ LiveData * Java8 Language Support * RxJava * ReactiveStreams ʹ͍ͭͯࠓճऔΓ্͛·ͤΜ
android.arch.lifecycle.LiveData<T> observe(@NonNull LifecycleOwner owner, @NonNull Observer<T> observer) ͜ͷLiveDataͷΛࢹ͢Δ ༩͑ΒΕͨLifeCycleOwnerͷϥΠϑαΠΫϧ ʹैͬͯɺobserverʹ௨͞ΕΔ
observerʹ௨͞ΕΔͷϥΠϑαΠΫϧ͕ ΞΫςΟϒͷͱ͖ͷΈ active
android.arch.lifecycle.LiveData<T> observeForever(@NonNull Observer<T> observer) ϥΠϑϥΠΫϧͷΞΫςΟϒঢ়ଶʹ͔͔ΘΒͣ௨Λड͚औΔ CREATED ͷঢ়ଶͰ௨Λड͚औΕΔ
android.arch.lifecycle.LiveData<T> onActive() ΞΫςΟϒঢ়ଶʹ͋ΔΦϒβʔόʔ͕1Ҏ্ʹͳͬͨࡍʹݺΕΔ onInactive() ΞΫςΟϒঢ়ଶʹ͋ΔΦϒβʔόʔ͕1ະຬʹͳͬͨࡍʹݺΕΔ getValue() ݱࡏͷΛฦ͢
android.arch.lifecycle.Observer<T> onChanged(@Nullable T t) ͕มߋ͞ΕͨࡍʹݺΕΔ LiveData ͔ΒͷΛड͚औΔγϯϓϧͳΠϯλϑΣʔε
android.arch.lifecycle.MutableLiveData<T> ௨ৗͷ LiveData ֎෦͔ΒΛઃఆͰ͖ͳ͍ MutableLiveData ֎෦͔ΒΛઃఆՄೳͳϝιουΛެ։͍ͯ͠Δ
android.arch.lifecycle.MutableLiveData<T> setValue(T value) Λઃఆ͢ΔʢϝΠϯεϨουͰݺͼग़͢͜ͱʣ postValue(T value) ϝΠϯεϨου֎͔ΒΛઃఆ͢Δࡍͷศརϝιου
android.arch.lifecycle.MediatorLiveData<T> addSource(@NonNull LiveData<S> source, @NonNull Observer<S> onChanged) LiveData ΛՃ͢Δ removeSource(@NonNull
LiveData<S> toRemote) LiveData Λআ͢Δ ෳͷ LiveData ΛଋͶͯཧͰ͖ΔΫϥε ܕͷҧ͏ෳͷLiveDataʹΠϕϯτΛͤ͞Δ͜ͱ͕Ͱ͖Δ
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ਪ
՝
՝ 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 ΛͬͯɺϥΠϑαΠΫϧ มߋ࣌ʹݱࡏͷϥΠϑαΠΫϧͷঢ়ଶΛϩάʹग़ྗ͢ΔΑ͏ʹ͢Δ • Ͱ͖ͨΒɺը໘Λดͨ͡Γɺ։͍ͨΓɺཪʹճͨ͠Γɺը໘Λճసͤͨ͞Γͯ͠ϥΠϑα ΠΫϧͷঢ়ଶ͕ͲͷΑ͏ʹมΘΔ͔Λ֬ೝ͢Δ
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
՝ 1 • ݱࡏ࣌ࠁͷ࣌ HH:MM Λը໘ʹදࣔ͢Δ࣌ܭΞϓϦΛ࡞Δ ʢϩέʔϧͳͲͷࡉ͔͍͜ͱؾʹ͠ͳ͍Ͱʣ activity_main.xml ͷ TextView
ʹదͳ id Λ͚ͭͯɺͦ͜ʹग़͢ • ·ͣɺݹ͍ํ๏ͰͬͯΈΔ • Ұྫͱͯ͠ɺ࣍ͷϖʔδʹ ClockLegacy ΫϥεΛهࡌ͍ͯ͠·͢ɻ • ͜ͷΫϥεΛίϐϖͯ͠ MainActivity ͔ΒͬͯԼ͍͞ • ࣗͰΓ͍ͨਓ͜ΕΛΘͣʹ͖ʹ࣮ͯ͘͠Ε͍͍ͯͰ͢ɻ
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
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
՝ 2 • ݹ͍ํ๏ ClockLegacy Ϋϥεͷ࣮Λ LiveData Ͱॻ͖͑ͯΈΔ • ClockLiveData
ΫϥεΛ࡞͢Δʢ࣍ͷϖʔδʹςϯϓϨ public class ClockLiveData extends LiveData<Date> { ... } • MainActivity ͷ onCreate ͷதͰ ClockLiveData ʹ observe ͢Δ ʢClockLegacy Λ͏ͷࢭΊΔʣ
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
՝ 2 ͷ 2 • ClockLiveDataͷonActive, onInactive ʹϩάΛૠೖ͠ɺ͍ͭݺΕͯ ͍Δ͔֬ೝ͠·͠ΐ͏ •
HomeϘλϯΛԡͯ͠Recent Apps͔Β෮ؼͨ͠ͱ͖ʹɺ࣌ͷදࣔͲ͏ͳ Δʁ • ͙͢ʹ෮ؼͤͨ͞߹ʁ͔ͬͯΒ෮ؼͤͨ͞߹ʁ • observe ϝιουͷΘΓʹ observeForever ϝιουΛͬͨΒʁ • ը໘Λճసͤͨ͞ͱ͖ʁ • MainActivity ͔Β ClockLiveData ʹ setValue ͠Α͏ͱͨ͠Βʁ
՝ 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
՝ 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
<?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
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
EOF