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.4k
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
280
Android TV - Japan Android Group 2016 Aug.
t_egg
0
570
DroidKaigi 2016 パフォーマンスを追求したAndroidアプリを作るには
t_egg
8
8.9k
Other Decks in Programming
See All in Programming
PHP 8.4の新機能「プロパティフック」から学ぶオブジェクト指向設計とリスコフの置換原則
kentaroutakeda
2
900
ニーリーにおけるプロダクトエンジニア
nealle
0
840
初学者でも今すぐできる、Claude Codeの生産性を10倍上げるTips
s4yuba
16
11k
XP, Testing and ninja testing
m_seki
3
250
10 Costly Database Performance Mistakes (And How To Fix Them)
andyatkinson
0
340
脱Riverpod?fqueryで考える、TanStack Queryライクなアーキテクチャの可能性
ostk0069
0
150
PicoRuby on Rails
makicamel
2
130
AI時代のソフトウェア開発を考える(2025/07版) / Agentic Software Engineering Findy 2025-07 Edition
twada
PRO
87
29k
PostgreSQLのRow Level SecurityをPHPのORMで扱う Eloquent vs Doctrine #phpcon #track2
77web
2
530
A full stack side project webapp all in Kotlin (KotlinConf 2025)
dankim
0
120
Systèmes distribués, pour le meilleur et pour le pire - BreizhCamp 2025 - Conférence
slecache
0
120
Google Agent Development Kit でLINE Botを作ってみた
ymd65536
2
250
Featured
See All Featured
Practical Tips for Bootstrapping Information Extraction Pipelines
honnibal
PRO
20
1.3k
GraphQLの誤解/rethinking-graphql
sonatard
71
11k
Reflections from 52 weeks, 52 projects
jeffersonlam
351
20k
Designing for humans not robots
tammielis
253
25k
Let's Do A Bunch of Simple Stuff to Make Websites Faster
chriscoyier
507
140k
Testing 201, or: Great Expectations
jmmastey
43
7.6k
実際に使うSQLの書き方 徹底解説 / pgcon21j-tutorial
soudai
PRO
181
54k
Save Time (by Creating Custom Rails Generators)
garrettdimon
PRO
31
1.3k
Making Projects Easy
brettharned
116
6.3k
Statistics for Hackers
jakevdp
799
220k
Practical Orchestrator
shlominoach
189
11k
Imperfection Machines: The Place of Print at Facebook
scottboms
267
13k
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