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.1k
Jetpack Compose の動画表示対応 をまとめてみた
Android Jetpack Compose で動画表示対応 をまとめました。
nagayan
September 01, 2023
Tweet
Share
Other Decks in Programming
See All in Programming
iOS 26にアップデートすると実機でのHot Reloadができない?
umigishiaoi
0
140
#QiitaBash MCPのセキュリティ
ryosukedtomita
1
1.5k
RailsGirls IZUMO スポンサーLT
16bitidol
0
200
Claude Code + Container Use と Cursor で作る ローカル並列開発環境のススメ / ccc local dev
kaelaela
12
7.2k
ISUCON研修おかわり会 講義スライド
arfes0e2b3c
1
470
バイブコーディング超えてバイブデプロイ〜CloudflareMCPで実現する、未来のアプリケーションデリバリー〜
azukiazusa1
2
590
Android 16KBページサイズ対応をはじめからていねいに
mine2424
0
480
バイブスあるコーディングで ~PHP~ 便利ツールをつくるプラクティス
uzulla
1
140
フロントエンドのパフォーマンスチューニング
koukimiura
5
2.1k
CDK引数設計道場100本ノック
badmintoncryer
2
490
High-Level Programming Languages in AI Era -Human Thought and Mind-
hayat01sh1da
PRO
0
900
レベル1の開発生産性向上に取り組む − 日々の作業の効率化・自動化を通じた改善活動
kesoji
1
310
Featured
See All Featured
Chrome DevTools: State of the Union 2024 - Debugging React & Beyond
addyosmani
7
750
Music & Morning Musume
bryan
46
6.7k
Product Roadmaps are Hard
iamctodd
PRO
54
11k
Distributed Sagas: A Protocol for Coordinating Microservices
caitiem20
331
22k
Faster Mobile Websites
deanohume
308
31k
Exploring the Power of Turbo Streams & Action Cable | RailsConf2023
kevinliebholz
34
5.9k
Visualizing Your Data: Incorporating Mongo into Loggly Infrastructure
mongodb
47
9.6k
ReactJS: Keep Simple. Everything can be a component!
pedronauck
667
120k
Building a Modern Day E-commerce SEO Strategy
aleyda
42
7.4k
Thoughts on Productivity
jonyablonski
69
4.7k
What’s in a name? Adding method to the madness
productmarketing
PRO
23
3.5k
The Power of CSS Pseudo Elements
geoffreycrofte
77
5.9k
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.