Slide 1

Slide 1 text

今後のJetpackで Android開発は こう変わる! 2019/09/10 ca.apk #8 Keita Kagurazaka

Slide 2

Slide 2 text

androidx.activity 1.0.0から

Slide 3

Slide 3 text

Fragmentのbackハンドリング

Slide 4

Slide 4 text

これまでのFragmentのbackハンドリング interface OnBackPressedListener { fun onBackPressed(): Boolean } // in Activity override fun onBackPressed() { supportFragmentManager.fragments.reversed().forEach { if (it.isVisible && it is OnBackPressedListener) { if (it.onBackPressed()) return } } super.onBackPressed() }

Slide 5

Slide 5 text

これからのFragmentのbackハンドリング // in Fragment override fun onAttach(context: Context) { super.onAttach(context) val onBackPressedCallback = requireActivity().onBackPressedDispatcher.addCallback(this) { // backが押されたときの処理 } Handler().postDelayed({ onBackPressedCallback.isEnabled = false }, 2000L) }

Slide 6

Slide 6 text

これからのFragmentのbackハンドリング // in Fragment override fun onAttach(context: Context) { super.onAttach(context) val onBackPressedCallback = requireActivity().onBackPressedDispatcher.addCallback(this) { // backが押されたときの処理 } Handler().postDelayed({ onBackPressedCallback.isEnabled = false }, 2000L) } LifecycleOwner

Slide 7

Slide 7 text

これからのFragmentのbackハンドリング // in Fragment override fun onAttach(context: Context) { super.onAttach(context) val onBackPressedCallback = requireActivity().onBackPressedDispatcher.addCallback(this) { // backが押されたときの処理 } Handler().postDelayed({ onBackPressedCallback.isEnabled = false }, 2000L) } callbackは有効なものが 登録逆順で呼び出される

Slide 8

Slide 8 text

androidx.activity 1.0.0 & androidx.fragment 1.1.0から

Slide 9

Slide 9 text

layout.xmlの指定

Slide 10

Slide 10 text

レイアウトIDコンストラクタ ● Activity or FragmentのコンストラクタにlayoutのリソースIDを 指定できるように ● setContentView or onCreateViewを省略できる ● Activityの場合DataBindingするのは面倒になる

Slide 11

Slide 11 text

ViewModelの取得方法

Slide 12

Slide 12 text

これまでのViewModel取得方法 // in Activity or Fragment private val viewModel: UserDetailViewModel by lazy { ViewModelProviders.of(this).get(UserDetailViewModel::class.java) } // in Fragment private val activityViewModel: UserDetailViewModel by lazy { ViewModelProviders.of(requireActivity()).get(UserDetailViewModel::class.java) } // in Fragment in Fragment private val parenttViewModel: UserDetailViewModel by lazy { ViewModelProviders.of(requireParentFragment()) .get(UserDetailViewModel::class.java) }

Slide 13

Slide 13 text

これからのViewModel取得方法 // in Activity or Fragment private val viewModel: UserDetailViewModel by viewModels() // in Fragment private val activityViewModel: UserDetailViewModel by activityViewModels() // in Fragment in Fragment private val viewModel: UserDetailViewModel by viewModels({ requireParentFragment() })

Slide 14

Slide 14 text

viewModelsの中身 @MainThread inline fun Fragment.viewModels( noinline ownerProducer: () -> ViewModelStoreOwner = { this }, noinline factoryProducer: (() -> Factory)? = null ) = createViewModelLazy(VM::class, { ownerProducer().viewModelStore }, factoryProducer)

Slide 15

Slide 15 text

viewModelsの中身 @MainThread inline fun Fragment.viewModels( noinline ownerProducer: () -> ViewModelStoreOwner = { this }, noinline factoryProducer: (() -> Factory)? = null ) = createViewModelLazy(VM::class, { ownerProducer().viewModelStore }, factoryProducer) ViewModelのscopeを決める

Slide 16

Slide 16 text

viewModelsの中身 @MainThread inline fun Fragment.viewModels( noinline ownerProducer: () -> ViewModelStoreOwner = { this }, noinline factoryProducer: (() -> Factory)? = null ) = createViewModelLazy(VM::class, { ownerProducer().viewModelStore }, factoryProducer) ViewModelのFactoryを指定する

Slide 17

Slide 17 text

androidx.fragment 1.2.0から (現在はalpha03)

Slide 18

Slide 18 text

Activity破棄対策

Slide 19

Slide 19 text

これまでのSavedStateのハンドリング in ViewModel // in Fragment override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) savedInstanceState?.let(viewModel::onRestoreInstanceState) } override fun onSaveInstanceState(outState: Bundle) { super.onSaveInstanceState(outState) viewModel.onSaveInstanceState(outState) }

Slide 20

Slide 20 text

これからのSavedStateのハンドリング in ViewModel class DetailViewModel( private val savedStateHandle: SavedStateHandle ) : ViewModel() { fun someProcess() { savedStateHandle.set("key_value", 100) val saved = savedStateHandle.get("key_value") } }

Slide 21

Slide 21 text

これからのSavedStateのハンドリング in ViewModel class DetailViewModel( private val savedStateHandle: SavedStateHandle ) : ViewModel() { fun someProcess() { savedStateHandle.set("key_value", 100) val saved = savedStateHandle.get("key_value") } } Bundleに入る値なら入れられる

Slide 22

Slide 22 text

これからのSavedStateのハンドリング in ViewModel class DetailViewModel( private val savedStateHandle: SavedStateHandle ) : ViewModel() { fun someProcess() { savedStateHandle.set("key_value", 100) val saved = savedStateHandle.get("key_value") } } Daggerの場合 -> Ask me later!

Slide 23

Slide 23 text

これまでのFragmentコンテナ

Slide 24

Slide 24 text

Fragment表示

Slide 25

Slide 25 text

これまでのFragmentコンテナ // in Activity supportFragmentManager.beginTransaction() .replace(R.id.content, HomeFragment(), null) .commit()

Slide 26

Slide 26 text

これからのFragmentコンテナ

Slide 27

Slide 27 text

これからのFragmentコンテナ Fragment transaction時の アニメーションを適切に ハンドリングしてくれる

Slide 28

Slide 28 text

androidx.lifecycle 2.1.0から

Slide 29

Slide 29 text

LiveDataのストリーム変換

Slide 30

Slide 30 text

これまでのLiveData transformations data class User(val name: String) // in ViewModel private val mutableUser = MutableLiveData() val user: LiveData = Transformations.map(mutableUser) { it.name }

Slide 31

Slide 31 text

これからのLiveData transformations data class User(val name: String) // in ViewModel private val mutableUser = MutableLiveData() val user: LiveData = mutableUser.map { it.name } .distinctUntilChanged()

Slide 32

Slide 32 text

LiveData transformations data class User(val name: String) // in ViewModel private val mutableUser = MutableLiveData() val user: LiveData = mutableUser.map { it.name } .distinctUntilChanged() ktxにLiveDataの 拡張関数として定義された

Slide 33

Slide 33 text

LiveData transformations data class User(val name: String) // in ViewModel private val mutableUser = MutableLiveData() val user: LiveData = mutableUser.map { it.name } .distinctUntilChanged() 待望のdistinctUntilChanged追加

Slide 34

Slide 34 text

kotlinx.coroutines

Slide 35

Slide 35 text

これまでのcoroutine起動 in ViewModel class DetailViewModel : ViewModel(), CoroutineScope { private val job = SupervisorJob() override val coroutineContext: CoroutineContext = Dispatchers.Main.immediate + job override fun onCleared() { cancel() } fun onClicked() { launch { // 色々 } } }

Slide 36

Slide 36 text

これからのcoroutine起動 in ViewModel // in ViewModel fun onClicked() { viewModelScope.launch { // 色々 } }

Slide 37

Slide 37 text

これからのcoroutine起動 in ViewModel // in ViewModel fun onClicked() { viewModelScope.launch { // 色々 } } onCleared()でキャンセルされる CoroutineScope

Slide 38

Slide 38 text

androidx.lifecycle 2.2.0から (現在はalpha04)

Slide 39

Slide 39 text

これまでのcoroutine起動 in LifecycleOwner class DetailFragment : Fragment(), CoroutineScope { private lateinit var job: Job override val coroutineContext get() = Dispatchers.Main + job override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) job = SupervisorJob() launch { … } } override fun onDestroy() { cancel() super.onDestroy() } }

Slide 40

Slide 40 text

これからのcoroutine起動 in LifecycleOwner class DetailFragment : Fragment() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) lifecycleScope.launch { // 色々 } } }

Slide 41

Slide 41 text

これからのcoroutine起動 in LifecycleOwner class DetailFragment : Fragment() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) lifecycleScope.launch { // 色々 } } } onDestroy()でキャンセルされる CoroutineScope

Slide 42

Slide 42 text

これからのcoroutine起動 in LifecycleOwner class DetailFragment : Fragment() { init { lifecycleScope.launchWhenStarted { // Fragment transactionなどのライフサイクル制限がある処理 } } }

Slide 43

Slide 43 text

これからのcoroutine起動 in LifecycleOwner class DetailFragment : Fragment() { init { lifecycleScope.launchWhenStarted { // Fragment transactionなどのライフサイクル制限がある処理 } } } onStart()で開始し、 onStop()でキャンセルされる coroutineを起動

Slide 44

Slide 44 text

まとめ ● MVVM with coroutines + LiveDataで書くための仕組みがそ ろってきた ● minSdkVersionを23にして、このスタイルで書くのが標準に なっていくでしょう

Slide 45

Slide 45 text

Thanks!