Slide 1

Slide 1 text

Architecture Components ษڧձ ͕͑Θ Θ͞ͼʔ; ͋Β͖ ͋Μ͍͟Ώ͖ ୈ3ճ໨ ViewModel

Slide 2

Slide 2 text

Architecture Componentsษڧձ ͱ͸ • Architecture Componentsͷجૅ஌ࣝʹֶ͍ͭͯͿษڧձ • ओ࠵ɿGDG Tokyo ϋογϡλά: #gdgtokyo • ߨࢣɺνϡʔλʔɿGoogleࣾһͱGoogle Developer Expert ʢ͋Μ͍͟Ώ͖ɺ ͕͑ΘɺΘ͞ͼʔ;ɺ͋Β͖ʣ • ౰೔νϡʔλʔɿ
 ɹ@satorufujiwaraɺ@STAR_ZEROɺ@95kugoɺ@zaki50ɺ@itog

Slide 3

Slide 3 text

Architecture Componentsษڧձ ͱ͸ • ܭ4ճͷ༧ఆ • ୈ1ճ:Handling Lifecycles • ୈ2ճ:LiveData • ୈ3ճ:ViewModel • ୈ4ճ:Room λΠϜςʔϒϧ 19:30ʙ19:35 ѫࡰˍઆ໌ 19:35ʙ20:15 ViewModel ͷઆ໌ 20:15ʙ20:25 ٳܜ 20:25ʙ ՝୊औΓ૊Έ

Slide 4

Slide 4 text

Download Android Studio 3.0.1 https://goo.gl/KmYZzW

Slide 5

Slide 5 text

Architecture Components ͱ͸ • ෳ਺ͷػೳɾϥΠϒϥϦͷ૯শ • Lifecycles • LiveData • ViewModel • Room • Paging

Slide 6

Slide 6 text

Architecture Components ͱ͸ • ෳ਺ͷػೳɾϥΠϒϥϦͷ૯শ • Lifecycles • LiveData • ViewModel • Room • Paging ݸผར༻OK

Slide 7

Slide 7 text

Architecture Components ͱ͸ • ෳ਺ͷػೳɾϥΠϒϥϦͷ૯শ • Lifecycles • LiveData • ViewModel • Room • Paging ݸผར༻OK ૊Έ߹Θͤར༻OK

Slide 8

Slide 8 text

Architecture Components ͱ͸ • ෳ਺ͷػೳɾϥΠϒϥϦͷ૯শ • Lifecycles • LiveData • ViewModel • Room • Paging ࠓ೔ͷςʔϚ͸͜Ε લճ ࣍ճ * RxJava * ReactiveStreams * Dagger ʹ͍ͭͯ͸ࠓճ͸औΓ্͛·ͤΜ

Slide 9

Slide 9 text

Architecture Components ͱ͸ • Google I/O 2017 Ͱൃදʢ1.0.0 alpha 1ʣ • ݱࡏͷ҆ఆόʔδϣϯ : 1.1.0 ʢ2018೥2݄22೔ʣ https://developer.android.com/topic/libraries/architecture/release-notes.html

Slide 10

Slide 10 text

Architecture Components ͷઃఆ dependencies { // ViewModel and LiveData implementation “android.arch.lifecycle:extensions:x.y.z" kapt “android.arch.lifecycle:compiler:x.y.z” } ϓϩδΣΫτͷ build.gradle https://developer.android.com/topic/libraries/architecture/adding-components.html

Slide 11

Slide 11 text

No content

Slide 12

Slide 12 text

Lifecycles ͓͞Β͍

Slide 13

Slide 13 text

Lifecycles • Lifecycles = Lifecycle-aware Components • ϥΠϑαΠΫϧΛݕ஌͢Δίϯϙʔωϯτ • Activity ΍ Fragment ͷϥΠϑαΠΫϧঢ়ଶ͕มΘͬͨͱ͖ʹԿ͔ ΞΫγϣϯΛى͜͢ɺͱ͍͏͜ͱ͕Ͱ͖ΔΑ͏ʹͳΔ

Slide 14

Slide 14 text

Lifecycle.State • ݱࡏͷϥΠϑαΠΫϧঢ়ଶΛද͢ enum • INITIALIZED • DESTROYED • CREATED • STARTED • RESUMED https://developer.android.com/topic/libraries/architecture/lifecycle.html

Slide 15

Slide 15 text

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

Slide 16

Slide 16 text

ݱࡏͷϥΠϑαΠΫϧΛऔಘ΍؂ࢹ͢Δ val state: Lifecycle.State = lifecycle.currentState // state.compareTo(Lifecycle.State.INITIALIZED) lifecycle.addObserver(object : LifecycleObserver { @OnLifecycleEvent(Event.ON_ANY) fun onAny(source: LifecycleOwner, event: Event) { // ... } })

Slide 17

Slide 17 text

LiveData ͓͞Β͍

Slide 18

Slide 18 text

ओͳLiveData • LiveData (android.arch.lifecycle) ௨ৗͷ LiveData • MutableLiveData (android.arch.lifecycle) ֎෦͔ΒมߋՄೳͳ LiveData • MediatorLiveData (android.arch.lifecycle) ෳ਺ͷ LiveData ΛଋͶͯ؅ཧ͢Δ LiveData

Slide 19

Slide 19 text

ViewModel

Slide 20

Slide 20 text

ViewModel • Activity ͷը໘ճస࣌ͷσʔλอ࣋ • Activity ͷෳ਺ Fragment ؒͰͷσʔλड͚౉͠ • LiveData ͱซ༻͢Δ͜ͱ͕ଟ͍ • ϓϩηεఀࢭޙ͸෮چͰ͖ͳ͍ • σʔλͷӬଓԽͰ͸ͳ͍

Slide 21

Slide 21 text

ViewModel

Slide 22

Slide 22 text

͜Ε·Ͱͷը໘ճసରԠ͸ʁ

Slide 23

Slide 23 text

͜Ε·Ͱͷը໘ճసରԠ͸ʁ • Activity#onSaveInstanceState() • FragmentActivity#onRetainCustomNonConfigurationInstance() • Fragment#setRetainInstance() • android:configChanges="orientation|keyboardHidden" • ݻఆ…

Slide 24

Slide 24 text

Activity#onSaveInstanceState()

Slide 25

Slide 25 text

class BeefActivity : AppCompatActivity() { companion object { private const val EXTRA_BEEF_KEY = "8044" } // ... public override fun onSaveInstanceState(outState: Bundle) { outState.putString(EXTRA_BEEF_KEY, beef.text as String) super.onSaveInstanceState(outState) } override fun onRestoreInstanceState(savedInstanceState: Bundle) { super.onRestoreInstanceState(savedInstanceState) beef.text = savedInstanceState.getString(EXTRA_BEEF_KEY) } } Activity#onSaveInstanceState() onRestoreInstanceStateͰ͸ͳ͘onCreate()Ͱ΋Մ

Slide 26

Slide 26 text

Activity#onSaveInstanceState() • ը໘ճస΍ΞϓϦόοΫάϥϯυޙͷϓϩηεఀࢭ͔Βσʔ λΛ෮چͰ͖Δɻ • ୯७Ͱগྔͷσʔλ޲͖
 ʢEditText ͷೖྗσʔλอ࣋΍εΫϩʔϧҐஔͳͲʣ • େ͖͍σʔλ΍ෳࡶͳσʔλ͸ Configuration Change தʹ ύϑΥʔϚϯε௿Լʹͭͳ͕Δ

Slide 27

Slide 27 text

FragmentActivity# onRetainCustomNonConfigurationInstance()

Slide 28

Slide 28 text

onRetainCustomNonConfigurationInstance() class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) } }

Slide 29

Slide 29 text

onRetainCustomNonConfigurationInstance() class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) } override fun onRetainCustomNonConfigurationInstance(): Any { return Dog("chip", 6) } } data class Dog(val name: String, val age: Int) อ͍࣋ͨ͠ΠϯελϯεΛฦ٫

Slide 30

Slide 30 text

onRetainCustomNonConfigurationInstance() class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) val dog = lastCustomNonConfigurationInstance as Dog? ?: Dog("wasa", 18) } override fun onRetainCustomNonConfigurationInstance(): Any { return Dog("chip", 6) } } data class Dog(val name: String, val age: Int) औಘ

Slide 31

Slide 31 text

onRetainCustomNonConfigurationInstance() • ը໘ճసޙͷσʔλ෮چͰ͖Δɻ • όοΫάϥϯυޙͷϓϩηεఀࢭ͔Β͸σʔλ෮چͰ ͖ͳ͍ • ը૾ͳͲͷେ͖ͳσʔλ΍ෳࡶͳσʔλ΋อ࣋Ͱ͖Δ • ͓खܰͳؾ͕͢Δ

Slide 32

Slide 32 text

Fragment#setRetainInstance()

Slide 33

Slide 33 text

@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) public class HolderFragment extends Fragment ɹɹɹɹɹɹɹɹɹɹɹɹɹɹɹɹɹimplements ViewModelStoreOwner { private static final String LOG_TAG = "ViewModelStores"; // ... public HolderFragment() { setRetainInstance(true); } // ... } Fragment#setRetainInstance() AACͷ಺෦࣮૷ΛҰ෦ൈਮ

Slide 34

Slide 34 text

Fragment#setRetainInstance() • ը໘ճసޙͷσʔλ෮چͰ͖Δɻ • όοΫάϥϯυޙͷϓϩηεఀࢭ͔Β͸σʔλ෮چͰ ͖ͳ͍ • ը૾ͳͲͷେ͖ͳσʔλ΍ෳࡶͳσʔλ΋อ࣋Ͱ͖Δ • ViewModel ͷ಺෦࣮૷Ͱ࢖ΘΕ͍ͯΔ

Slide 35

Slide 35 text

ViewModel

Slide 36

Slide 36 text

ViewModelͷܧঝ ୯७ʹViewModelΛܧঝ͢Δ # View΍ActivityContext͸࣋ͬͯ͸͍͚ͳ͍ data class User(val name: String, val age: Int) class UserViewModel : ViewModel() { private var user: MutableLiveData? = null fun getUser() { if (user == null) { user = MutableLiveData() load() } } private fun load() { // ... } }

Slide 37

Slide 37 text

ViewModelΛΠϯελϯεԽ val user = ViewModelProviders.of(this).get(UserViewModel::class.java) user.getUser()?.observe(this, Observer { it -> // Log.d("BEEF", "$it") }) ViewModelProvidersΛ࢖ͬͯΠϯελϯεԽ͢Δ # ৄࡉ͸ޙड़

Slide 38

Slide 38 text

class UserViewModel : ViewModel() { // ... } ViewModel#onCleared()ͰϦʔΫ๷ࢭ

Slide 39

Slide 39 text

class UserViewModel : ViewModel() { var disposables = CompositeDisposable() // ... override fun onCleared() { super.onCleared() // ϦʔΫ๷ࢭ౳ɺղ์͢Δ৔߹͸͜͜Ͱɻ disposables.dispose() } } ViewModel#onCleared()ͰϦʔΫ๷ࢭ

Slide 40

Slide 40 text

AndroidViewModel

Slide 41

Slide 41 text

AndroidViewModelͷܧঝ class DogsViewModel(app: Application) : AndroidViewModel(app) { @Inject lateinit var repo: DogRepository var dogs: MutableLiveData? = null init { // (app as BeefApp).applicationInjector() as AppComponent } // ... } ViewModel಺ͰApplication͕ඞཁͳ৔߹ʹ࢖͑Δ

Slide 42

Slide 42 text

AndroidViewModelΛΠϯελϯεԽ val dogs = ViewModelProviders.of(this).get(DogsViewModel::class.java) dogs.getUser()?.observe(this, Observer { it -> // Log.d("DACHSHUND", "$it") }) લड़ͷViewModelͱҰॹͰ͢ # ৄࡉ͸ޙड़

Slide 43

Slide 43 text

ViewModelProvider /s

Slide 44

Slide 44 text

ViewModelProvider /sͰΠϯελϯεԽ val user = ViewModelProviders.of(this).get(UserViewModel::class.java) ViewModel͸ViewModelProviderܦ༝Ͱ ΠϯελϯεԽ͠ͳ͚Ε͹͍͚·ͤΜ val user = UserViewModel()

Slide 45

Slide 45 text

val user = ViewModelProviders.of(this) .get(UserViewModel::class.java) val user = ViewModelProviders.of() .get(::class.java) ViewModelProvider /s ViewModelProviders.of()ʹࢦఆͰ͖Δͷ͸ FragmentActivity͔Fragment͚ͩ

Slide 46

Slide 46 text

ViewModelProviders#of() @NonNull @MainThread public static ViewModelProvider of(@NonNull Fragment fragment) {} @NonNull @MainThread public static ViewModelProvider of(@NonNull FragmentActivity activity) {} @NonNull @MainThread public static ViewModelProvider of(@NonNull Fragment fragment, @NonNull Factory factory) {} @NonNull @MainThread public static ViewModelProvider of(@NonNull FragmentActivity activity, @NonNull Factory factory) {} Fragment͔FragmentActivityͷΈαϙʔτ͍ͯ͠Δ

Slide 47

Slide 47 text

val user = ViewModelProviders.of() .get(::class.java) val user = ViewModelProviders.of(this) .get(UserViewModel::class.java) ViewModelProvider /s ViewModelProvider.get()ʹ͸ ViewModelΛܧঝͨ͠ΫϥεΛࢦఆ͢Δ

Slide 48

Slide 48 text

ViewModelProvider /s class MyDogFragment : Fragment() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val userA = ViewModelProviders.of(this).get(UserViewModel::class.java) val userB = ViewModelProviders.of(activity!!).get(UserViewModel::class.java) } } userAͱuserB͸Πϯελϯε͕ҧ͍ ViewModelProviders.of()ʹ౉ͨ͠ΫϥεʹΑͬͯΠϯελϯε͕ܾ·Δ

Slide 49

Slide 49 text

ViewModelProvider.Factory

Slide 50

Slide 50 text

ViewModelProvider.Factory val user = ViewModelProviders.of(this).get(UserViewModel::class.java) ViewModelProviders.of()ʹ͸ୈೋҾ਺͕ࢦఆͰ͖ͯ ViewModelͷੜ੒ํ๏ΛมߋͰ͖Δ

Slide 51

Slide 51 text

ViewModelProvider.Factory val user = ViewModelProviders.of(this).get(UserViewModel::class.java)

Slide 52

Slide 52 text

val user = ViewModelProviders.of(this, object : ViewModelProvider.Factory { override fun create(modelClass: Class): T { // Կ͔͠Βॲཧ @Suppress("UNCHECKED_CAST") return UserViewModel(repo) as T } }).get(UserViewModel::class.java) ViewModelProvider.Factoryͷࢦఆ

Slide 53

Slide 53 text

ViewModelProvider.Factoryͷܧঝ class UserViewModelFactory @Inject constructor(val repo: UserRepository) : ViewModelProvider.Factory { @Suppress("UNCHECKED_CAST") override fun create(modelClass: Class): T { return UserViewModel(repo) as T } } ViewModelProvider.FactoryΛܧঝͯ͠Ҿ਺Λ༩͑ͨΓ΋Ͱ͖Δ Dagger౳ͰɺFactoryʹ@Singleton͚ͭͯ؅ཧͨ͠Γ ViewModel΋Injectͨ͠Γ͢Δ৔߹͸ɺ͜ͷܧঝ͕ඞཁʹͳΓ·͢ https://github.com/googlesamples/android-architecture-components/blob/master/GithubBrowserSample/app/src/main/java/com/android/example/github/viewmodel/GithubViewModelFactory.java

Slide 54

Slide 54 text

ViewModelProvider.Factoryؔ࿈ /** * Simple factory, which calls empty constructor on the give class. */ public static class NewInstanceFactory implements Factory {} /** * {@link Factory} which may create {@link AndroidViewModel} and * {@link ViewModel}, which have an empty constructor. */ public static class AndroidViewModelFactory extends ViewModelProvider.NewInstanceFactory {} ͦͷଞ

Slide 55

Slide 55 text

՝୊ http://bit.ly/AAC-VM

Slide 56

Slide 56 text

՝୊ 0 http://bit.ly/AAC-VM

Slide 57

Slide 57 text

՝୊ 0 • Empty Activity Ͱ৽͍͠KotlinϓϩδΣΫτΛ࡞Δ ʢύοέʔδ໊͸ com.sample.viewmodel Λ૝ఆʣ // build.gradle apply plugin: 'kotlin-kapt' dependencies { implementation "com.android.support:appcompat-v7:27.0.2" // … implementation "android.arch.lifecycle:extensions:1.1.0" kapt "android.arch.lifecycle:compiler:1.1.0" } http://bit.ly/AAC-VM

Slide 58

Slide 58 text

՝୊ 1 http://bit.ly/AAC-VM

Slide 59

Slide 59 text

՝୊ 1 • ViewModelΛܧঝͨ͠UserViewModelʹॻ͖׵͑ͯΈΑ͏ class UserViewModel { private var user: User? = null fun getUser(): User? { if (user == null) { load() } return user } private fun load() { user = User("Hanyu", 23) } } data class User(val name: String, val age: Int) http://bit.ly/AAC-VM

Slide 60

Slide 60 text

՝୊ 1 (ྫ) class UserViewModel : ViewModel() { private var user: MutableLiveData? = null fun getUser(): MutableLiveData? { if (user == null) { user = MutableLiveData() load() } return user } private fun load() { user?.postValue(User("Hanyu", 23)) } } data class User(val name: String, val age: Int) http://bit.ly/AAC-VM

Slide 61

Slide 61 text

՝୊ 1 - 2 • ܧঝͨ͠UserViewModelΛActivity಺Ͱ࢖ͬͯΈΑ͏ class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) val user = UserViewModel() Log.d("OLYMPICS", user.getUser()?.toString()) } } http://bit.ly/AAC-VM

Slide 62

Slide 62 text

՝୊ 1 - 2 (ྫ) class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) val user = ViewModelProviders.of(this).get(UserViewModel::class.java) user.getUser()?.observe(this, Observer { Log.d(“OLYMPICS", it?.toString()) }) } } http://bit.ly/AAC-VM

Slide 63

Slide 63 text

՝୊ 1 - 3 • ը໘ճసͯ͠΋ಉ͡Πϯελϯε͔Ͳ͏͔֬ೝͯ͠ΈΑ͏ コレで回転 http://bit.ly/AAC-VM

Slide 64

Slide 64 text

՝୊ 2 http://bit.ly/AAC-VM

Slide 65

Slide 65 text

՝୊ 2 • Fragment ಺Ͱ userA/B/C ͕ಉ͔֬͡ೝ͠Α͏ class DogFragment : Fragment() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val userA = ViewModelProviders.of(this).get(UserViewModel::class.java) val userB = ViewModelProviders.of(activity!!).get(UserViewModel::class.java) val userC = ViewModelProviders.of(this).get(UserViewModel::class.java) } } http://bit.ly/AAC-VM

Slide 66

Slide 66 text

՝୊ 3 http://bit.ly/AAC-VM

Slide 67

Slide 67 text

՝୊ 3 • 2ͭͷFragment ಺Ͱ user ͕ಉ͔֬͡ೝ͠Α͏ class TopFragment : Fragment() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val user = ViewModelProviders.of(this).get(UserViewModel::class.java) } } class BottomFragment : Fragment() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val user = ViewModelProviders.of(this).get(UserViewModel::class.java) } } http://bit.ly/AAC-VM

Slide 68

Slide 68 text

ViewModelProvider /s ෮श class MyDogFragment : Fragment() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val userA = ViewModelProviders.of(this).get(UserViewModel::class.java) val userB = ViewModelProviders.of(activity!!).get(UserViewModel::class.java) } } userAͱuserB͸Πϯελϯε͕ҧ͍ ViewModelProviders.of()ʹ౉ͨ͠ΫϥεʹΑͬͯΠϯελϯε͕ܾ·Δ

Slide 69

Slide 69 text

Thanks. twitter.com/wasabeef_jp wasabeef.jp github.com/wasabeef