Slide 1

Slide 1 text

2023/6/15 日本経済新聞社 Androidチーム 篠原裕矢 トップ画面の RecyclerView に Compose を一部導入した話

Slide 2

Slide 2 text

ハッシュタグ #nikkei_tech_talk 自己紹介 2 ● 2020 年 4 月に日経入社(新卒 4 年目) ● Android チームで日経電子版と紙面ビューアーを開発 ● ラーメンとカレーと日本酒が好き

Slide 3

Slide 3 text

ハッシュタグ #nikkei_tech_talk 1. 電子版トップ画面構成について 2. Jetpack Compose の導入ステップ 3. RecyclerView へ Compose を導入する実装方法 アジェンダ 3

Slide 4

Slide 4 text

ハッシュタグ #nikkei_tech_talk ● 基本的な RecyclerView の仕組み ○ onBindViewHolder 、onCreateViewHolder のタイミング ● Compose の LazyColumn 、 LazyRow の仕組み ● 複雑な UI を Compose で記述する方法 今日話さないこと 4

Slide 5

Slide 5 text

ハッシュタグ #nikkei_tech_talk 1. 電子版トップ画面構成について 2. Jetpack Compose の導入ステップ 3. RecyclerView へ Compose を導入する実装方法 アジェンダ 5

Slide 6

Slide 6 text

ハッシュタグ #nikkei_tech_talk 電子版トップの画面例( RecyclerView ) 6

Slide 7

Slide 7 text

ハッシュタグ #nikkei_tech_talk 7 現時点でどこが Compose ?

Slide 8

Slide 8 text

ハッシュタグ #nikkei_tech_talk Compose を導入済みのアイテム 8 ヘッダー 画像バナー

Slide 9

Slide 9 text

ハッシュタグ #nikkei_tech_talk 電子版トップ画面の特徴 9 ● ユーザーの PV 数が最も多い画面の 1 つ ● 重要度の高いニュースが並ぶ ● 変更頻度が高い ● RecyclerView の Adapter で管理する表示アイテムが 20 種 類近くある ○ 記事、バナー、ヘッダー、広告など

Slide 10

Slide 10 text

ハッシュタグ #nikkei_tech_talk 1. 電子版トップ画面構成について 2. Jetpack Compose の導入ステップ 3. RecyclerView へ Compose を導入する実装方法 アジェンダ 10

Slide 11

Slide 11 text

ハッシュタグ #nikkei_tech_talk 11 Android View RecyclerView Android View Android View ComposeView RecyclerView Android View Android View ComposeView LazyColumn ComposeView ComposeView 導入前 部分的導入 完全移行 Jetpack Compose の導入ステップ

Slide 12

Slide 12 text

ハッシュタグ #nikkei_tech_talk Jetpack Compose の導入ステップ 12 Android View RecyclerView Android View Android View ComposeView RecyclerView Android View Android View ComposeView LazyColumn ComposeView ComposeView 紹介 導入前 部分的導入 完全移行

Slide 13

Slide 13 text

ハッシュタグ #nikkei_tech_talk Compose 導入前の構成 13 ● ViewBinding + ListAdapter の構成 ○ Groupie や Epoxy などのサードパーティライブラリを使わない素 の RecyclerView ● 表示アイテムのレイアウトはすべて xml で記述 ○ 20種類近くの表示アイテムあり

Slide 14

Slide 14 text

ハッシュタグ #nikkei_tech_talk Compose 部分的導入後の構成 14 ● ViewBinding + AbstractComposeView + ListAdapter の 構成 ● 表示アイテムのレイアウトは xml または Compose で記述 ○ 20種類近くの表示アイテムあり ● アイテム管理などの仕組みは RecyclerView を踏襲

Slide 15

Slide 15 text

ハッシュタグ #nikkei_tech_talk なぜ部分的に導入したか 15 ● Full Compose な画面に一括で変更するには工数がかかる ● 複雑な UI のアイテムも多く、変更頻度が高い画面である ○ 20種類近くの UI パーツがある ○ 最も訪問される画面なのでリスクが高い ● Compose の技術潮流に乗るべく、安全に導入して少しずつ移 行したい ● 作った UI を別の Compose な画面において再利用可能

Slide 16

Slide 16 text

ハッシュタグ #nikkei_tech_talk 1. 電子版トップ画面構成について 2. Jetpack Compose の導入ステップ 3. RecyclerView へ Compose を導入する実装方法 アジェンダ 16

Slide 17

Slide 17 text

ハッシュタグ #nikkei_tech_talk 事前準備 〜ライブラリアップデート〜 17 ● Compose UI のバージョンを 1.2.0 以上に上げる ● RecyclerView のバージョンを 1.3.0 以上に上げる ● dependencies にて下記記述 implementation "androidx.compose.ui:ui:1.2.0" implementation "androidx.recyclerview:recyclerview:1.3.0"

Slide 18

Slide 18 text

ハッシュタグ #nikkei_tech_talk 事前準備 〜ライブラリアップデート〜 18 ● RecyclerView と Compose が協調して動作するようになり、 View が画面外に移動したときの再利用が効率的になる ● 詳しくは各ライブラリのリリースノート👇 ○ https://developer.android.com/jetpack/androidx/releases/compose- ui#1.2.0-alpha06 ○ https://developer.android.com/jetpack/androidx/releases/recyclervie w#recyclerview-1.3.0-beta01

Slide 19

Slide 19 text

ハッシュタグ #nikkei_tech_talk 事前準備 〜ライブラリアップデート〜 19 ● Compose UI 1.2.0 ○ RecyclerView などの PoolingContainer を適切に処理する DisposeOnDetachedFromWindowOrReleasedFromPool と いう新しい ViewCompositionStrategy が追加された ● RecyclerView 1.3.0 ○ PoolingContainer の修正など、Compose UI 1.2.0 に対応した View 再利用の実装

Slide 20

Slide 20 text

ハッシュタグ #nikkei_tech_talk 実装方法 〜 ViewHolder の作成 〜 20 ● ViewBinding 用の ViewHolder と Compose 用の ViewHolder ● Compose 用 のViewHolder には AbstractComposeView を渡す class ViewBindingHolder( val binding: ViewBinding, ) : RecyclerView.ViewHolder(binding.root) class ComposeViewHolder( val abstractComposeView: AbstractComposeView, ) : RecyclerView.ViewHolder(abstractComposeView)

Slide 21

Slide 21 text

ハッシュタグ #nikkei_tech_talk 実装方法 21 ● onCreateViewHolder で ViewType に応じて ViewBindingHolder or ComposeViewHolder を返す override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { return when (ViewType.from(viewType)) { ViewType.HEADLINE_ARTICLE -> { val layoutInflater = LayoutInflater.from(parent.context) ViewBindingHolder(ArticleBinding.inflate(layoutInflater, parent, false)) } ViewType.HEADLINE_HEADER -> { ComposeViewHolder(HeaderComposeView(parent.context)) } } }

Slide 22

Slide 22 text

ハッシュタグ #nikkei_tech_talk 実装方法 22 ● onBindViewHolder で型チェックをする ● ViewBindingHolder or ComposeViewHolder で bind 処理を実行する override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { val item = getItem(position) when (holder) { is ViewBindingHolder -> holder.bind(item) is ComposeViewHolder -> holder.bind(item) } }

Slide 23

Slide 23 text

ハッシュタグ #nikkei_tech_talk 実装方法 23 ● ヘッダーの ComposeView に定義した bind メソッドを呼ぶ fun ComposeViewHolder.bind(item: NewsItem) { // Composeで実装されているRecyclerViewのアイテムがbind対象 when (item) { is NewsItem.HeadlineHeader -> { (abstractComposeView as HeaderComposeView).bind(item.headerItem) } is NewsItem.HeadlineBanner -> { (abstractComposeView as BannerComposeView).bind(item.bannerItem) } else -> {} } }

Slide 24

Slide 24 text

ハッシュタグ #nikkei_tech_talk class HeaderComposeView @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyle: Int = 0, ) : AbstractComposeView(context, attrs, defStyle) { private var headerItem by mutableStateOf(null) @Composable override fun Content() { AppTheme { Header( headerItem = headerItem, ) } } fun bind(headerItem: HeaderItem) { this.headerItem = headerItem } } 実装方法 〜 ヘッダーの ComposeView 〜 24 Content() の中で Composable 関数が書ける

Slide 25

Slide 25 text

ハッシュタグ #nikkei_tech_talk 実装方法 25 @Composable fun Header( headerItem: HeaderItem?, modifier: Modifier = Modifier, ) { // Text、Button、RowなどのComposable関数を自由に書いてレイアウトを作成する } トップ画面以外にも レイアウトを流用できる

Slide 26

Slide 26 text

ハッシュタグ #nikkei_tech_talk まとめ 26 ● RecyclerView に Compose を導入していく方法を紹介しまし た ● 部分的な導入は実装コストも低いのでぜひ皆さんもやっていきま しょう💪 ● Compose を例としてモダンな技術をプロダクトに入れていく チームの流れがあり、楽しい開発ができます!

Slide 27

Slide 27 text

ハッシュタグ #nikkei_tech_talk 27 ご清聴ありがとうございました