Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Jetpack Composeにおける画像ライブラリ ~Coilに🤏だけ詳しくなる~/ #nikkei_tech_talk

Jetpack Composeにおける画像ライブラリ ~Coilに🤏だけ詳しくなる~/ #nikkei_tech_talk

2023/06/15開催、NIKKEI Tech Talk #8登壇資料です #nikkei_tech_talk
タイトルは「Jetpack Composeにおける画像ライブラリ ~Coilに🤏だけ詳しくなる~」です
https://nikkei.connpass.com/event/284090/

More Decks by 日本経済新聞社 エンジニア採用事務局

Other Decks in Technology

Transcript

  1. 2023/6/15
    日本経済新聞社 Androidチーム
    小倉 悠里
    Jetpack Composeにおける画像ライブラリ
    ~Coilに🤏だけ詳しくなる~
    NIKKEI TECH TALK #8

    View Slide

  2. ハッシュタグ #nikkei_tech_talk
    自己紹介
    名前:小倉 悠里(おぐら ゆり)
    経歴:
    ・2020年7月 ◁⚪◻ボタンとの初めての出会い
    ・2023年2月 日本経済新聞社に中途入社
    好きな食べ物:枝豆
    2
    小倉なのであんこの写真
    @姫路の御座候工場

    View Slide

  3. ハッシュタグ #nikkei_tech_talk
    日経電子版アプリ ver.6.23.0 ~
    電子版タブに画像バナーが登場🎉
    本バナーから特集ページを閲覧したり、
    クロスワードパズルに挑戦したりできるように😉
    電子版タブのRecyclerViewにJetpack Composeを
    一部導入した流れで、本バナーもComposeで実装
    その際の検討内容などを共有していきます!
    何の話?
    3

    View Slide

  4. ハッシュタグ #nikkei_tech_talk
    Jetpack Compose における画像ライブラリは2択
    インターネットから画像を読み込みたい
    4
    ライブラリ Coil Glide
    github https://github.com/coil-kt/coil https://github.com/bumptech/glide
    最新 io.coil-kt:coil-compose:2.4.0
    com.github.bumptech.glide:compose:
    1.0.0-alpha.3
    特徴 高速、軽量、使いやすい、モダン
    滑らかなスクロールと速度を
    最重視して開発されている
    豆知識
    💡
    Coroutine Image Loader の
    頭文字から命名
    開発を行っていたBumpをGoogleが買収済み
    (READMEの免責事項には、
    ”This is not an official Google product.” と記載...)

    View Slide

  5. ハッシュタグ #nikkei_tech_talk
    日経電子版アプリではCoilを選択
    ● GlideはJetpack Compose用にまだStable版が出ていない
    ● Coilが提供するKotlin-firstなAPIは、
    Kotlinで記述するComposeと相性が良い
    ● Now in Android でもCoilを使用
    ● 日経電子版のWearアプリにて導入済み(右画像)
    Coil vs Glide
    5

    View Slide

  6. ハッシュタグ #nikkei_tech_talk
    Coil
    使用するAPIは3種類
    ● AsyncImage
    ● SubcomposeAsyncImage
    ● AsyncImagePainter
    ○ 低レベルAPI
    ○ AsyncImageもSubcomposeAsyncImageも
    内部的にはAsyncImagePainterを使用している
    6

    View Slide

  7. ハッシュタグ #nikkei_tech_talk
    Coil 〜AsyncImage〜
    ● 非同期的にリクエストと描画を行うAPI
    ● foundationのImageコンポーザブルとほぼ似た使い勝手
    + placeholderやエラー画像などをPainterで指定したり、
    読み込み状態の変更を受け取ったりできる
    7
    AsyncImage(
    model = ImageRequest.Builder(LocalContext.current)
    .data("https://example.com/image.jpg")
    .crossfade(true)
    .build(),
    placeholder = painterResource(R.drawable.placeholder),
    contentDescription = stringResource(R.string.description),
    contentScale = ContentScale.Crop,
    modifier = Modifier.clip(CircleShape)
    )

    View Slide

  8. ハッシュタグ #nikkei_tech_talk
    【AsyncImageとの違いをざっくり理解】
    ● AsyncImage:placeholder / error / fallbackをPainterでセット
    ● SubcomposeAsyncImage:
    placeholder / error / fallbackをComposable関数でセット(Slot API)
    Coil 〜SubcomposeAsyncImage〜
    8
    SubcomposeAsyncImage(
    model = "https://example.com/image.jpg",
    contentDescription = stringResource(R.string.description)
    ) {
    val state = painter.state
    if (state is AsyncImagePainter.State.Loading || state is AsyncImagePainter.State.Error) {
    CircularProgressIndicator()
    } else {
    SubcomposeAsyncImageContent()
    }
    }

    View Slide

  9. ハッシュタグ #nikkei_tech_talk
    【もう少し詳しく理解】
    ● SubcomposeLayoutを利用したAsyncImage
    Coil 〜SubcomposeAsyncImage〜
    9
    ● サイズの計算はLayoutステップの中で行われている
    ● SubcomposeLayoutでは、Compositionステップを親のLayoutステップまで
    遅らせることで、constraints(制約≒サイズ)の取得を行える
    https://developer.android.com/jetpack/compose/layouts/basics

    View Slide

  10. ハッシュタグ #nikkei_tech_talk
    Coil
    〜Subcompose
    AsyncImage〜
    10
    @Composable
    fun SubcomposeAsyncImage(
    model: Any?,
    contentDescription: String?,
    imageLoader: ImageLoader,
    modifier: Modifier = Modifier,
    transform: (State) -> State = DefaultTransform,
    onState: ((State) -> Unit)? = null,
    alignment: Alignment = Alignment.Center,
    contentScale: ContentScale = ContentScale.Fit,
    alpha: Float = DefaultAlpha,
    colorFilter: ColorFilter? = null,
    filterQuality: FilterQuality = DefaultFilterQuality,
    content: @Composable SubcomposeAsyncImageScope.() -> Unit,
    ) {
    ...
    if (sizeResolver !is ConstraintsSizeResolver) {
    Box(...) { ... } // ※2
    } else {
    BoxWithConstraints(
    modifier = modifier,
    contentAlignment = alignment,
    propagateMinConstraints = true
    ) { ... }
    }
    }
    SubcomposeAsyncImageの中身を
    覗いてみると...👀
    BoxWithConstraints(※1)
    が使われている!
    ※1:SubcomposeLayoutを利用したComposable
    ※2:厳密にはSubcomposeAsyncImageでも、
    ImageRequestにサイズを明示的に指定した場合には、
    constraints取得が不要なためSubcompositionを
    使用しない

    View Slide

  11. ハッシュタグ #nikkei_tech_talk
    AsyncImage vs SubcomposeAsyncImage
    Q. Subcomposition、強そうなのでとりあえず使っておけば良い?
    A. No 🥺
    Subcompositionは拡張性は高いが、パフォーマンスコスト大
    ● painterで事足りるケースではAsyncImageを使用
    ● Success, Loading, Errorといった描画状態ごとにComposableを用いた表現を行
    いたい場合は、SubcomposeAsyncImageを使用💯
    ただし、パフォーマンスに注意(リスト中に多用しないなど)
    11

    View Slide

  12. ハッシュタグ #nikkei_tech_talk
    【仕様】
    - バナー画像:アスペクト比を保ったまま
     (paddingありで)画面横幅いっぱいに表示したい
     アスペクト比は、レスポンスで画像URLとともに取得される
    - placeholder:バナー画像のサイズで外枠をつけたい
    日経での導入談
    12

    View Slide

  13. ハッシュタグ #nikkei_tech_talk
    placeholder表示にあたり、端末の横幅(親レイアウトのサイズ)が必要 🤔
    日経での導入談
    13
    SubcomposeAsyncImage(
    modifier = modifier.padding( … )
    .aspectRatio((featuredContentsImage.width / featuredContentsImage.height).toFloat()),
    model = ImageRequest.Builder(LocalContext.current).data(featuredContentsImage.url).build(),
    contentDescription = featuredContentsBanner.alt,
    ) {
    if (painter.state is AsyncImagePainter.State.Success) {
    SubcomposeAsyncImageContent()
    } else {
    Image(
    modifier = Modifier.border(BorderStroke(1.dp, colorResource(id = R.color.placeholder_border))),
    painter = painterResource(id = placeHolder),
    contentDescription = featuredContentsBanner.alt,
    )
    }
    }

    View Slide

  14. ハッシュタグ #nikkei_tech_talk
    まとめ
    ● 画像読み込みライブラリ for Compose:Coil vs Glide
    ● CoilのAsyncImage vs SubcomposeAsyncImage
    ● SubcomposeAsyncImageの使い所の見極めが大事👀
    ● NIKKEIでは、新しいUIにはComposeを積極採用するなど
    モダンな技術を積極的に取り入れている
    14

    View Slide

  15. 15
    ありがとうございました

    View Slide