Starting a coroutine inside onBindViewHolder creates a mess with recycler

一世执手 提交于 2020-01-16 09:08:18

问题


I am developing a chat application and there is a specific API so some things i must implement them with a specific way. For example (and the case that i have a problem...)

When i have to display an Image the API says that i have to split the Image in small chunks and store them as a message with a byteArray content. There is also a header message that its body is the messageIds of the fileChunks. So in the RecyclerView inside the onBindViewHolder, when i see a header file message (msgType == 1) then i start a coroutine to fetch the chunkFile messages by the ids, construct the File and then switch to the MainDispatcher, and so the Image with Glide using a BitmapFactory.decodeByteArray. The code is shown below

messageItem.message?.msgType == MSG_TYPE_FILE -> {
     holder.sntBody.text = "Loading file"

     val fileInfo = Gson().fromJson(URLDecoder.decode(messageItem.message?.body, "UTF-8"), FileInformation::class.java)

     job = chatRoomAdapterScope.launch(Dispatchers.IO) {
    // i get the messageIds of the chunks from Header message
    val segSequence = fileInfo.seg.split(",").map { it.toLong() }

    // i get the fileChunks from Database
    val fileChunks = AppDatabase.invoke(mContext).messageDao().getMessageById(segSequence)
    val compactFile = ByteArrayOutputStream()

    // Reconstruct the file
    for (chunk in fileChunks)
        compactFile.write(Base64.decode(chunk.fileBody, Base64.DEFAULT))

        withContext(Dispatchers.Main) {
            val bitmapOptions = BitmapFactory.Options().apply {
                inSampleSize = 8
            }

        Glide.with(mContext).asBitmap()
            .load(BitmapFactory.decodeByteArray(compactFile.toByteArray(), 0, compactFile.size(), bitmapOptions)!!)
            .fitCenter()
            .into(object : SimpleTarget<Bitmap>() {
                 override fun onResourceReady(resource: Bitmap, transition: Transition<in Bitmap>?) {
                    holder.sntImageView.setImageBitmap(resource)
                    holder.sntImageView.visibility = View.VISIBLE
                 }
             })
              holder.sntBody.text = fileInfo.filename
       }
    }
}

My problem is that when i scroll fast the image that is supposed to be loaded in an item appears in another item. My first guess is that the Coroutine that started from a specific item didnt complete as soon as the item was recycled so when the coroutine finished it had a reference to a new item, so i added the
holder.itemView.addOnAttachStateChangeListener method as some people commented, to cancel the coroutine when the item is recycled. However i didn't work. Is there any idea of why that may happens and if there is a better implementation of the proccess according to the specific API...?

来源:https://stackoverflow.com/questions/57952131/starting-a-coroutine-inside-onbindviewholder-creates-a-mess-with-recycler

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!