Android 在onViewDetachedFromWindow中取消特定ViewHolder的特定协同路线

Android 在onViewDetachedFromWindow中取消特定ViewHolder的特定协同路线,android,kotlin,android-recyclerview,kotlin-coroutines,Android,Kotlin,Android Recyclerview,Kotlin Coroutines,(经编辑的问题……) 我正在开发一个聊天应用程序,有一个特定的API,所以有些事情我必须以特定的方式实现它们。例如(在我有问题的情况下…) 当我必须显示一个图像时,API说我必须将图像分成小块,并将它们存储为带有byteArray内容的消息。还有一个头消息,它的主体是filechunk的messageid。因此,在onBindViewHolder内部的RecyclerView中,当我看到头文件消息(msgType==1)时,我启动一个协同程序,通过ID获取chunkFile消息,构造文件,然后切

(经编辑的问题……) 我正在开发一个聊天应用程序,有一个特定的API,所以有些事情我必须以特定的方式实现它们。例如(在我有问题的情况下…)

当我必须显示一个图像时,API说我必须将图像分成小块,并将它们存储为带有byteArray内容的消息。还有一个头消息,它的主体是filechunk的messageid。因此,在onBindViewHolder内部的RecyclerView中,当我看到头文件消息(msgType==1)时,我启动一个协同程序,通过ID获取chunkFile消息,构造文件,然后切换到MainDispatcher,然后使用BitmapFactory.decodeByteArray使用Glide创建图像。代码如下所示

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
       }
    }
}
messageItem.message?.msgType==MSG\u TYPE\u文件->{
holder.sntBody.text=“正在加载文件”
val fileInfo=Gson().fromJson(urldecker.decode(messageItem.message?.body,“UTF-8”),FileInformation::class.java)
job=聊天室适配器scope.launch(Dispatchers.IO){
//我从头消息中获取块的messageid
val segSequence=fileInfo.seg.split(“,”).map{it.toLong()}
//我从数据库中获取文件块
val fileChunks=AppDatabase.invoke(mContext.messageDao().getMessageById(segSequence)
val compactFile=ByteArrayOutputStream()
//重建文件
for(文件块中的块)
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(对象:SimpleTarget(){
覆盖资源就绪(资源:位图,转换:转换?){
holder.sntImageView.setImageBitmap(资源)
holder.sntImageView.visibility=View.VISIBLE
}
})
holder.sntBody.text=fileInfo.filename
}
}
}
我的问题是,当我快速滚动时,应该加载到某个项目中的图像会出现在另一个项目中。我的第一个猜测是,从某个特定项目开始的协同程序并没有在该项目回收后立即完成,因此当协同程序完成时,它引用了一个新项目,因此我添加了 holder.itemView.addOnAttachStateChangeListener方法,正如一些人评论的那样。但是我没有工作。
是否知道为什么会发生这种情况,以及根据特定的API是否有更好的过程实现…?

我认为您可以使用
查看。OnAtachStateChangeListener

override fun onBindViewHolder() {
    if(messageType == TYPE_FILE) {
        val job = chatRoomAdapterScope.launch(Dispatchers.IO) {
            val fileChunks = AppDatabase.invoke(MyApplication.instance).messageDao()
                .getMessageByMessageId(segSequence)
            // do some heacy work with the fileChunks
            withContext(Dispatchers.Main) {
                // holder set up
            }
        }
        holder.itemView.addOnAttachStateChangeListener(object : View.OnAttachStateChangeListener {
            override fun onViewDetachedFromWindow(view: View) {
                view.removeOnAttachStateChangeListener(this)
                job.cancel()
            }

            override fun onViewAttachedToWindow(p0: View?) {}
        })
    }
}

我不知道那个技巧。我会试试看,让你知道。。!谢谢你,我的朋友。我建议你从适配器中取出该协程,并在presenter/viewmodel中编写代码,然后再进行渲染。最好的解决方案是将该协程移出适配器。但是如果你想用性能和回收来交换,那么你可以用:holder.setIsRecyclable(false)来禁用它。有没有一个简单的代码示例,我从你们那里得到的,因为我是一个协同程序和其他东西的乞丐。。。?顺便说一句,有很多!!