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
Jetpack Compose の動画表示対応 をまとめてみた
Search
nagayan
September 01, 2023
Programming
0
1.2k
Jetpack Compose の動画表示対応 をまとめてみた
Android Jetpack Compose で動画表示対応 をまとめました。
nagayan
September 01, 2023
Tweet
Share
Other Decks in Programming
See All in Programming
SourceGeneratorのススメ
htkym
0
200
例外処理とどう使い分ける?Result型を使ったエラー設計 #burikaigi
kajitack
16
6.1k
高速開発のためのコード整理術
sutetotanuki
1
410
React 19でつくる「気持ちいいUI」- 楽観的UIのすすめ
himorishige
11
7.5k
AgentCoreとHuman in the Loop
har1101
5
250
LLM Observabilityによる 対話型音声AIアプリケーションの安定運用
gekko0114
2
440
CSC307 Lecture 09
javiergs
PRO
1
840
カスタマーサクセス業務を変革したヘルススコアの実現と学び
_hummer0724
0
740
CSC307 Lecture 05
javiergs
PRO
0
500
生成AIを使ったコードレビューで定性的に品質カバー
chiilog
1
280
フロントエンド開発の勘所 -複数事業を経験して見えた判断軸の違い-
heimusu
7
2.8k
The Past, Present, and Future of Enterprise Java
ivargrimstad
0
620
Featured
See All Featured
Data-driven link building: lessons from a $708K investment (BrightonSEO talk)
szymonslowik
1
920
Typedesign – Prime Four
hannesfritz
42
3k
Darren the Foodie - Storyboard
khoart
PRO
2
2.4k
Art, The Web, and Tiny UX
lynnandtonic
304
21k
Navigating Team Friction
lara
192
16k
The World Runs on Bad Software
bkeepers
PRO
72
12k
Bioeconomy Workshop: Dr. Julius Ecuru, Opportunities for a Bioeconomy in West Africa
akademiya2063
PRO
1
57
"I'm Feeling Lucky" - Building Great Search Experiences for Today's Users (#IAC19)
danielanewman
231
22k
Pawsitive SEO: Lessons from My Dog (and Many Mistakes) on Thriving as a Consultant in the Age of AI
davidcarrasco
0
68
AI Search: Where Are We & What Can We Do About It?
aleyda
0
7k
The untapped power of vector embeddings
frankvandijk
1
1.6k
Max Prin - Stacking Signals: How International SEO Comes Together (And Falls Apart)
techseoconnect
PRO
0
89
Transcript
株式会社 Gunosy テクノロジー本部 永山 雄 2023年9月1日 Jetpack Compose の動画表示対応 をまとめてみた
(C) Gunosy Inc. All Rights Reserved. PAGE | 2 ▪
名前:nagayan / 永山 雄 ▪ 所属:株式会社Gunosy – Android エンジニア auサービスToday を担当 ▪ X:@nagayan_dev 自己紹介
(C) Gunosy Inc. All Rights Reserved. PAGE | 3 アジェンダ
背景・方針 Jetpack Compose の動画実装 • Exoplayer、AndroidViewを使った、基本実装 • デフォルトの動画パーツを OFF にする • VideoStateの定義と実装 • 動画パーツの実装 • 動画の進捗とシークバーを連動させる • ライフサイクルで再生・停止・解放 まとめ
(C) Gunosy Inc. All Rights Reserved. PAGE | 4 ▪
auサービスTodayでは Compose 実装への置き換えを随時進めて います ▪ Jetpack Compose の動画実装を調べていましたが、情報が散見 されていました ▪ 動画部分のCompose化をしたため、その対応をまとめました ▪ 既存のデザインを踏襲するため、デフォルトの動画パーツは使用し ない方針です 背景・方針
(C) Gunosy Inc. All Rights Reserved. PAGE | 5 ▪
Android Jetpack Compose で動画表示 – https://tech.gunosy.io/entry/android_compose_video_player 今回の内容
(C) Gunosy Inc. All Rights Reserved. Jetpack Compose の動画実装
(C) Gunosy Inc. All Rights Reserved. PAGE | 7 dependencies
{ implementation "androidx.media3:media3-exoplayer:1.1.1" 使用するライブラリ Jetpack Compose の動画実装
(C) Gunosy Inc. All Rights Reserved. PAGE | 8 val
exoPlayer = remember(context) { ExoPlayer.Builder(context).build().apply { setMediaItem(MediaItem.fromUri(Uri.parse(url))) prepare() seekTo(0L) } } Exoplayer、AndroidViewを使った、基本実装 Jetpack Compose の動画実装 ▪ 動画を再生する Exoplayerを 作成します
(C) Gunosy Inc. All Rights Reserved. PAGE | 9 Exoplayer、AndroidViewを使った、基本実装
Jetpack Compose の動画実装 ▪ 作成したExoplayerを、 AndroidView の PlayerView に設定します val exoPlayer = remember(context) ~~~ Box(~~~) { AndroidView( modifier = ~~~, factory = { context -> PlayerView(context).apply { this.player = exoPlayer } })}
(C) Gunosy Inc. All Rights Reserved. PAGE | 10 パーツがデフォルトのもの
→パーツを自前実装する Jetpack Compose の動画実装 Exoplayer、AndroidViewを使った、基本実装
(C) Gunosy Inc. All Rights Reserved. PAGE | 11 val
exoPlayer = remember(context) ~~~ Box(~~~) { AndroidView( modifier = ~~~, factory = { context -> PlayerView(context).apply { useController = false this.player = exoPlayer } })} デフォルトの動画パーツを OFF にする Jetpack Compose の動画実装 ▪ PlayerView の useController を false に指定することで、デ フォルトの動画パーツを非表 示にできます
(C) Gunosy Inc. All Rights Reserved. PAGE | 12 ▪
UIを更新するため、独自の VideoState を定義します ▪ remember で State を保持します VideoStateの定義と実装 Jetpack Compose の動画実装 var videoState by remember { mutableStateOf(VideoState.LOADING) } enum class VideoState { LOADING, PAUSE, START, ENDED }
(C) Gunosy Inc. All Rights Reserved. PAGE | 13 ▪
onPlaybackStateChan ged で VideoState の 更新をします。 VideoStateの定義と実装 Jetpack Compose の動画実装 exoPlayer.addListener(object : Player.Listener { override fun onPlaybackStateChanged(playbackState: Int) { videoState = when { playbackState == Player.STATE_READY && playWhenReady -> VideoState.START playbackState == Player.STATE_ENDED && playWhenReady -> VideoState.ENDED ~~~ -> VideoState.LOADING ~~~ --> VideoState.PAUSE
(C) Gunosy Inc. All Rights Reserved. PAGE | ▪ 再生停止ボタンを実装します
▪ 先ほどの State を元に、Start と Pause を切り替えます 14 動画パーツの実装 Jetpack Compose の動画実装 var videoState by remember { ~~~ } ~~~ if (videoState == VideoState.START) { Image( painter = ~中断ボタン画像~, contentDescription = ~~~, ) } else { Image( painter = ~再生ボタン画像~, contentDescription = ~~~, ) } ~~~
(C) Gunosy Inc. All Rights Reserved. PAGE | 15 動画パーツの実装
Jetpack Compose の動画実装 var currentTime by remember { mutableStateOf(0L) } ~~~ Slider( ~~~ value = currentTime.toFloat(), valueRange = 0f..exoPlayer.duration.~~~, colors = SliderDefaults.colors( ~~~ ))} ▪ シークバーの実装です ▪ Slider を用いて実装します ▪ 動画の進捗度として currentTime を定義します ▪ Slider の value に指定し、 valueRange は 0 から 動画 の長さを設定します
(C) Gunosy Inc. All Rights Reserved. PAGE | 16 ▪
シークバーの操作を反映させ ます ▪ onValueChange はシーク バー操作時に通知される Callback で、ここで通知され た値を currentTime に設定し ます 動画の進捗とシークバーを連動させる Jetpack Compose の動画実装 var currentTime by remember { mutableStateOf(0L) } ~~~ Slider( ~~~ value = currentTime.toFloat(), onValueChange = { timeMs -> val time = timeMs.toLong() exoPlayer.seekTo(time) currentTime = time }, valueRange = 0f..exoPlayer.duration.~~~, ~~~
(C) Gunosy Inc. All Rights Reserved. PAGE | 17 ▪
動画が再生されてても、シーク バーが動いてくれません ▪ 再生状態の時に LaunchedEffect 内で repeat をし、動画時間を取得して currentTime に反映させます。 動画の進捗とシークバーを連動させる Jetpack Compose の動画実装 var currentTime by remember { mutableStateOf(0L) } ~~~ if (videoState == VideoState.START) { LaunchedEffect(Unit) { repeat(Int.MAX_VALUE) { delay(1000) currentTime = exoPlayer.contentPosition }}}
(C) Gunosy Inc. All Rights Reserved. PAGE | 18 ▪
アプリがバックグラウンドに行っ た時に再生しっぱなしになってし まう ▪ DisposableEffect を用いて、ラ イフサイクルに合わせて処理を 実行 – onResume:再生 – onPause:停止 ライフサイクルで再生・停止・解放 Jetpack Compose の動画実装 DisposableEffect(lifecycleOwner) { val observer = LifecycleEventObserver { _, event -> if (event == Lifecycle.Event.ON_RESUME) { if (videoState == VideoState.START) { exoPlayer.play() } } else if (event == Lifecycle.Event.ON_PAUSE) { exoPlayer.pause() } } lifecycleOwner.lifecycle.addObserver(observer) ~~~
(C) Gunosy Inc. All Rights Reserved. PAGE | 19 ▪
DisposableEffect の onDispose で解放処理を実行 します ライフサイクルで再生・停止・解放 Jetpack Compose の動画実装 DisposableEffect(lifecycleOwner) { ~~~ onDispose { exoPlayer.run { playWhenReady = false ~~~ release() } lifecycleOwner.lifecycle.removeObserver(observer) } }
(C) Gunosy Inc. All Rights Reserved. PAGE | 20 完成
Jetpack Compose の動画実装
(C) Gunosy Inc. All Rights Reserved. PAGE | 21 ▪
Jetpack Compose で基本的な動画表示の実装について紹介しま した ▪ デフォルトの動画パーツを表示するだけなら簡単に実装できます が、カスタマイズしたパーツを表示するとなるとちょっと工夫が必要 になります ▪ 動画再生が一定時間経過した後に動画パーツを非表示にしたり、 動画終了時に End Screen を表示できるようになれば、より高機 能な動画が実現できると思います まとめ Jetpack Compose ライフを楽しみましょう!
中表紙 情報を世界中の人に最適に届ける (C) Gunosy Inc. All Rights Reserved.