19
15

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Google I/O 2018アプリで使われているAdapterのクリックイベントをViewModelで受け取り、LiveDataを使ってFragment/Activityに通知する

Posted at

Google I/O 2018 のセッションスケジュールなどがみれるアプリがかなり勉強になるので、ソースコードを読んでて学んだことを一つ書いてみようと思います。

アプリのダウンロードはこちら

ソースコードはこちら

AdapterのクリックイベントをViewModelで受け取り、LiveDataを使ってFragment/Activityに通知する

MVVMアーキテクチャとして基本的なロジックはViewModelに書きます。
ですが、画面遷移などViewに関わる処理はFragment or Activityでないと画面遷移できません。

ViewModelからViewへの処理はDatabinding経由でやることになっているので直接ViewModelからViewの処理を呼び出すことはできません。
なので、GoogleI/OアプリはLiveDataを使ってその辺りを解決しています。

例えばスケジュールを詳細を開く時のタップイベントはViewModelで受け取るようにして、ViewModelでLiveDataを使って変更をFragmentに検知させて画面遷移をしています。

スケジュールアイテムをタップする

ViewModelのメンバ変数にLiveDataのメンバ変数を設定

実際のソースコードに載せていきます。

ViewModelのメンバ変数にLiveDataのメンバ変数を設定しています。

  • ScheduleViewModel.kt

private val _navigateToSessionAction = MutableLiveData<Event<String>>()
val navigateToSessionAction: LiveData<Event<String>>
   get() = _navigateToSessionAction

FragmentでLiveDataの変更をObserveする

FragmentでLiveDataの変更をobserveする

  • ScheduleFragment.kt
scheduleViewModel.navigateToSessionAction.observe(this, EventObserver { sessionId ->
       openSessionDetail(sessionId)
})

この設定をした時点で ScheduleViewModel の中で navigateToSessionActionsetValue された時点でFragmentに通知されて openSessionDetail(sessionId) メソッドが呼び出されることになります。 ( openSessionDetail メソッドでは中で startActivity が実行されています。

RecyclerViewAdapterでのアイテムのタップイベントを検知してViewModelで受け取る

ViewModelの中で setValue をどういう風に呼び出すかというとこれもDatabindingを使ってうまくアーキテクチャにのせています。

ScheduleViewModel クラスは ScheduleEventListener というinterfaceを実装しています。

この実装の中の openEventDetail メソッドで setValue() が実行されています。

override fun openEventDetail(id: SessionId) {
   _navigateToSessionAction.value = Event(id)
}

RecylerViewAdapterにアイテムのタップイベントを設定する

セッションのアイテムは ScheduleDayFragment.kt クラスにてRecyclerViewを生成する処理が実装されています。
正確にいうと ScheduleFragment.ktScheduleDayFragment を生成しています。

これは上タブを実装するために、ViewPagerを使っているからです。

ScheduleDayFragment.kt をみていきます。

ScheduleDayAdapter にviewModelをコンストラクタとして渡していますが、実際には ScheduleEventListener の実装を渡しています。

  • ScheduleDayFragment.kt
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    adapter = ScheduleDayAdapter(
         viewModel,
         tagViewPool,
         viewModel.showReservations,
         viewModel.timeZoneId,
         this)
}

ScheduleDayAdapterの中でeventListenerをbindする

  • item_session.xml
<data>
   <variable
       name="eventListener"
       type="com.google.samples.apps.iosched.ui.sessioncommon.EventActions" />
</data>

・・・・・・・・もろもろのレイアウトの実装・・・・・・・・・・

<!--ここにタップイベントが仕込まれている↓-->
<androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="?selectableItemBackground"
        android:onClick="@{() -> eventListener.openEventDetail(userSession.session.id)}"
        android:paddingEnd="@dimen/spacing_normal"
        android:paddingVertical="@dimen/spacing_normal"
        tools:targetApi="o">

xml内の android:onClick を使ってボタンのタップイベントを仕込んでいます。

この仕込まれたタップイベントをRecyclerViewAdapterのViewHolderで引数で渡ってきた ScheduleEventListener をbindしています。


fun bind(userSession: UserSession) {
   binding.userSession = userSession
   // ↓ここで引数をバインドしている
   binding.eventListener = eventListener
   binding.showReservations = showReservations
   binding.timeZoneId = timeZoneId
   binding.setLifecycleOwner(lifecycleOwner)
   binding.executePendingBindings()
}

(このコードなぜか apply を使ってかかれていないのは謎です........)

これで全てが連動されてタップイベントがFragmentで実行されていることになります。

まとめ

  • ViewModelにLiveDataのメンバ変数を設定
  • FragmentでLiveDataの変数が setValue されるのをobserveする
  • ViewModelの側でボタンのタップイベントを検知するinterfaceを実装している
  • ViewModelの実装をRecylerViewAdapterに引数として渡す
  • RecylerViewAdapterで生成する子のViewに引数で渡ってきたリスナーをDatabindingを使ってセットしてクリックイベントを発火させる

これから

次はDaggaar2でDIしている箇所をちゃんと理解したい。
ここを理解できたら「Google I/Oアプリ完全に理解したわー」になれる気がする。

19
15
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
19
15

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?