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
240
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
マルチモジュールにおけるテスト最適化
fxwx23
0
210
エンジニア1年目で複雑なコードの改善に取り組んだ話
mtnmr
3
2k
Developer Joy == Developer Productivity (really!)
hollycummins
1
220
いつか使える ObjectSpace / Maybe useful ObjectSpace
euglena1215
2
140
Modern Angular with the NGRX Signal Store New Rules for Your Architecture @BASTA! 2024 in Mainz
manfredsteyer
PRO
0
150
はじめてみよう量子プログラミング
itokoichi01
0
210
Lessons by WebAssembly app in production on CDN Edge Computing Service
tetsuharuohzeki
0
210
Increased Performance and Developer Productivity with Jakarta EE 11
ivargrimstad
0
380
エラーレスポンス設計から考える、0→1開発におけるGraphQLへの向き合い方
bicstone
5
1.5k
Evolution of real-time – Irina Nazarova, EuRuKo, 2024
irinanazarova
0
120
watsonx.ai Dojo #2 生成AIを使ったアプリ開発入門編
oniak3ibm
PRO
0
180
メモリ最適化を究める!iOSアプリ開発における5つの重要なポイント
yhirakawa333
0
420
Featured
See All Featured
Building a Scalable Design System with Sketch
lauravandoore
459
32k
YesSQL, Process and Tooling at Scale
rocio
167
14k
The Brand Is Dead. Long Live the Brand.
mthomps
53
38k
How GitHub (no longer) Works
holman
310
140k
Why You Should Never Use an ORM
jnunemaker
PRO
53
8.9k
GitHub's CSS Performance
jonrohan
1030
450k
Stop Working from a Prison Cell
hatefulcrawdad
267
20k
[RailsConf 2023] Rails as a piece of cake
palkan
48
4.6k
The Language of Interfaces
destraynor
153
23k
How to Think Like a Performance Engineer
csswizardry
16
960
Side Projects
sachag
451
42k
Build The Right Thing And Hit Your Dates
maggiecrowley
30
2.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