androidx / media

Jetpack Media3 support libraries for media use cases, including ExoPlayer, an extensible media player for Android
https://developer.android.com/media/media3
Apache License 2.0
1.69k stars 404 forks source link

Library and just sample support for alternative BitmapLoaders #121

Open yschimke opened 2 years ago

yschimke commented 2 years ago

Use case description

Apps typically have some image loading library. These libraries may do a few things

1) Cache images to avoid re-requesting 2) Allow customising image loading, such as failure images, or transformations 3) Use existing HTTP clients, including any interceptors, such as enforcing SSL.

Proposed solution

Show an example of using a typical image loader such as Coil.

/*
 * Copyright 2022 Google Inc. All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 */

import android.content.Context
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.drawable.BitmapDrawable
import android.net.Uri
import androidx.media3.session.BitmapLoader
import coil.ImageLoader
import coil.request.ErrorResult
import coil.request.ImageRequest
import com.google.common.util.concurrent.ListenableFuture
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.guava.future
import java.io.IOException

class CoilBitmapLoader(
    private val imageLoader: ImageLoader,
    private val context: Context,
    private val coroutineScope: CoroutineScope,
) : BitmapLoader {
    override fun decodeBitmap(data: ByteArray): ListenableFuture<Bitmap> {
        return coroutineScope.future {
            val bitmap = BitmapFactory.decodeByteArray(data,  /* offset= */0, data.size)

            bitmap ?: throw IOException("Unable to decode bitmap")
        }
    }

    override fun loadBitmap(uri: Uri): ListenableFuture<Bitmap> = coroutineScope.future {
        val request = ImageRequest.Builder(context)
            .data(uri)
            .allowHardware(false)
            .build()

        val response = imageLoader.execute(request)
        val bitmap = (response.drawable as? BitmapDrawable)?.bitmap
        bitmap
            ?: throw IOException("Unable to load bitmap " + (response as? ErrorResult)?.throwable)
    }
}

and in MediaSessionService

    override fun onCreate() {
        super.onCreate()

        setMediaNotificationProvider(DefaultMediaNotificationProvider(application, CoilBitmapLoader(
            ImageLoader(this), application, this.lifecycleScope)))
    }

Alternatives considered

This is already possible, feel free to close, or advise if the code above is correct.

christosts commented 2 years ago

Thank you for pointing this. I'm marking the issue as a documentation candidate. I'll try to include a seminal implementation with Glide too.

christosts commented 2 years ago

On your implementation: