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
2.5k
9
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
GDG Tokyo Android Architecture Components - LiveData
GDG Tokyo Techtalk Android Architecture Components - LiveData on Jan 24, 2018.
Takashi EGAWA
January 24, 2018
More Decks by Takashi EGAWA
See All by Takashi EGAWA
Fuchsia Shibuya.apk #28 2018.9.28
t_egg
1
320
Android TV - Japan Android Group 2016 Aug.
t_egg
0
610
DroidKaigi 2016 パフォーマンスを追求したAndroidアプリを作るには
t_egg
8
9k
Other Decks in Programming
See All in Programming
A2UI という光を覗いてみる
satohjohn
1
140
ユニットテストの先へ:テスト技法で要求・仕様を整理するJava開発実践 / Beyond_Unit_Testing_Practical_Java_Development_Techniques_for_Organizing_Requirements_and_Specifications
shimashima35
0
410
Signal Forms: Details & Live Coding @enterJS 2026 in Mannheim
manfredsteyer
PRO
0
160
不変条件と整合性境界—ビジネスが決める設計判断と実現パターン / Invariants and Consistency Boundaries
nrslib
13
5.5k
Snowflake Summitでの新機能 CoCo / CoWork / snowflake-summit-2026-overall-what-new-coco
tatsuhiro
1
150
Skillsは効率化、Agentsは"自分の拡張"——Builder時代のエージェント編成(CC Night 2026)
wemra
1
140
セキュリティの専門家じゃなくてもできる。「セキュリティ意識」をアップデートして サプライチェーン攻撃への耐性を高めよう。
tk3fftk
5
880
そのテスト、説明できますか?~LWテスト戦略FW~のご紹介
nakahara
0
150
ローカルLLMを使ってB2Bサービスを作っていての学び
yaotti
0
200
jQueryをバージョンアップする前に使いたいjQuery Migrate
matsuo_atsushi
0
560
CSC307 Lecture 17
javiergs
PRO
0
320
Make SRE Operations Easier with Azure SRE Agent
kkamegawa
0
6.7k
Featured
See All Featured
Tips & Tricks on How to Get Your First Job In Tech
honzajavorek
1
540
Tell your own story through comics
letsgokoyo
1
960
Design and Strategy: How to Deal with People Who Don’t "Get" Design
morganepeng
133
19k
Abbi's Birthday
coloredviolet
2
8.1k
How to Grow Your eCommerce with AI & Automation
katarinadahlin
PRO
1
210
The agentic SEO stack - context over prompts
schlessera
0
820
Code Reviewing Like a Champion
maltzj
528
40k
Mozcon NYC 2025: Stop Losing SEO Traffic
samtorres
1
260
How STYLIGHT went responsive
nonsquared
100
6.2k
Why You Should Never Use an ORM
jnunemaker
PRO
61
9.9k
How to train your dragon (web standard)
notwaldorf
97
6.7k
Done Done
chrislema
186
16k
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