Search code examples
androidandroid-roomkotlin-coroutinesandroid-paging

Querying rows multiple times from ROOM database while using a Bitmap Type Converter class is crashing the App


So I have Recycler View with a paging adapter, the recycler view list item has an imageView and a couple of text views. The data for the textViews are being retrieved by the adapter from another ROOM Database whereas the images for each those specific list items are being retrieved from another ImageHolder ROOM Database.

In the onBind method of the adapter in addition to binding the textViews there is a separate call to the ImageHolder ROOM Database for the associated image. The Recycler View has about 100 items and while the UI is scrolled quickly, about 100 queries are made to the ImageHolder Database. This works fine but it slows down the app as the user scrolls and crashes the app. How do I do avoid the crash?

Here is the code:

The data class

@Entity(tableName = IMAGE_HOLDER_TABLE)
data class ImageHolder(

    @PrimaryKey(autoGenerate = false)
    var contentId: String = "",
    var imageBitmap : Bitmap,  // I am using a Converter class to convert a Bitmap to a ByteArray
    var timeStamp : Long = System.currentTimeMillis()
)

The Dao Interface

@Dao
interface ImageHolderDatabaseDao {

    @Query("SELECT * FROM $IMAGE_HOLDER_TABLE WHERE contentId = :contentId")
    suspend fun getImageHolder(contentId : String): ImageHolder

    @Query("SELECT imageBitmap FROM $IMAGE_HOLDER_TABLE WHERE contentId = 
    :contentId")
    suspend fun getImage(contentId : String): Bitmap
}

The method to get the image in the Adapter's onBindViewHolder method

val imageHolderDatabase = ImageHolderDatabase.instance(getApplicationContext())
    val imageHolderDatabaseDao = imageHolderDatabase.databaseDao
    private val scope = CoroutineScope(Dispatchers.Main +  
CoroutineName("notificationsAdapterCoroutine"))

    private fun populatePhotoFromLocalDb(senderUserId : String) {
        scope.launch {
            val imageBitmap = imageHolderDatabase.withTransaction {
                imageHolderDatabaseDao.getImageHolder(senderUserId)
            }

            Glide.with(getApplicationContext())
                .load(imageBitmap.imageBitmap)
                .placeholder(R.drawable.black_color_rectangle)
                .apply(glideRequestOptionsForCache)
                .transition(DrawableTransitionOptions.withCrossFade(glideCrossFadeDuration))
                .listener(glideFinishedLoadingListener(senderUserId, true, null))
                .into(binding.image)
        }
    }
//I am using the Paging 3 adapter to populate the textViews from another Room Database

I realize there are 100 query calls made to the ImageHolder Room Database since there are 100 items in the Recycler View. I am using Glide but not using its Caching for now.

What is a memory-efficient way to do this?


Solution

  • The type converter from ByteArray to Bitmap is causing too much memory usage, this is actually a good way to store images but the wrong use case for using the handy Type converters for ROOM (unless it's used in a non recyclerView adapter), I have instead changed the logic to store the downloadUrls only in the Room Db and using glide to load images via the download Url since glide has offline cache system built in, this logic works even with the internet being unavailable temporarily...