从回调 Kotlin 中获取价值

getting value from callback kotlin

提问人:JSONParser 提问时间:2/28/2023 最后编辑:JSONParser 更新时间:3/19/2023 访问量:149

问:

尝试制作一个文件 downloadManager

我们有一个包含 Recycler 视图的活动,Recycler 视图中的每个项目都代表一个处于下载、下载状态的文件。每个回收器视图项都有一个回调,此回调有 3 个信息:onSuccess (file)、onError(Error)、progress(Int)。 现在我想在 BindViewHolder 中提取此信息以显示进度,但我无法在回调中获取值: (为简单起见,删除其他代码)

  class DownloadActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
      
        val list = mutableListOf<DItem>()
        list.add(DItem("url", callback = object : Listener{
            override fun onSuccess(file: File) {

            }

            override fun onFailure(error: Error) {
            }

            override fun onProgress(progress: Int) {
            }
        })
      // trigger from here for simplicity otherwise each list item has a download button which will trigger this:
      FileDownloadManager().download("utl", list[0].callback)
    }

// adapter
    class DownloadAdapter : RecyclerView.Adapter<MyViewhOdler>() {

  
    val list = mutableListOf<DItem>()
   

    override fun onBindViewHolder(holder: MyViewhOdler, position: Int) {
// how to get value here:
        list.get(0).callback
    }

 
} 
          

class FileDownloadManager {

  
     override fun download(url: String, callback: Listener) {

       // on donwloading start, will trigger
       // callback.progress(<some value>)

    }

   

    interface Listener{
        fun onSuccess(file: File)
        fun onFailure(error: Error)
        fun onProgress(progress: Int)
    }

   
}
    
    // Ditem
     data class DItem (
   var url: String? = null,
    var callback: Listener,
       var fcallback: ((File, Error, Int)-> Unit)

)

    }
Kotlin 匿名类

评论

0赞 Silvio Mayolo 2/28/2023
冒着陈述显而易见的风险,该类是否有一个称为 ?仅存在具有该名称的构造函数参数并不意味着它是实例变量。DItemcallback
0赞 JSONParser 2/28/2023
@SilvioMayolo是的,它是公开的,添加了它
0赞 buhtz 3/20/2023
热烈欢迎来到SO。请尽量使用正确的大写字母,例如在标题、句子或单词“I”的开头。这对你的读者来说是温和的。请阅读如何提问最小可重复示例。然后用代码更新您的问题,向我们展示您到目前为止尝试过的内容。

答:

1赞 MDG 3/19/2023 #1

如果我理解正确,您想在“onBindViewHolder()”中获取“progress”值,但您不知道该怎么做。

我首先想到的一件事,不是修改大部分代码,但也可能是一个肮脏的解决方案,是:

您稍后实际上定义了对象回调,因此构造函数将不再接受“callback”,而是稍后将初始化的 var。

class DItem(
    var url: String? = null,
    var fcallback: ((File, Error, Int) -> Unit)
) {
    lateinit var callback: FileDownloadManager.Listener
}

此时,在“onBindViewHolder()”中,您现在可以定义回调并在该位置获取值:

fun onBindViewHolder() {
    println("onBindViewHolder")
    list[0].callback = object : FileDownloadManager.Listener {
        override fun onSuccess(file: File) {
        }
        override fun onFailure(error: Error) {
        }
        override fun onProgress(progress: Int) {
            print("progress: $progress")
        }
    }
}

我希望我确实正确地理解了这个问题,我真的想强调这样一个事实,即这不一定是一个干净的解决方案,而是实现速度最快且代码重构量最少的解决方案之一。

评论

0赞 JSONParser 3/20/2023
谢谢,但这会导致错误,假设我们有 10 个项目开始在屏幕上下载,假设屏幕只能显示 3 个项目,所以只有 3 个项目的 bindviewholder 将被调用(假设用户已打开屏幕并保持空闲状态没有滚动),但剩余的 7 个将尝试下载,但它们的回调未初始化,因此会导致文件管理器下载方法崩溃。
3赞 dominicoder 3/19/2023 #2

我认为您的问题源于这样一个事实,即您的适配器中有一个具有复杂行为的模型列表,其中应该是非常愚蠢的视图模型,仅表示每个列表项的当前状态。

onBindViewHolder只是为了将给定位置的项目的当前状态拍打到同一位置的匹配视图。它不应该保留回调或尝试更新自己。

您可以尝试将域模型包装在一个对象中,该对象保持当前的进度状态,然后通知所属适配器是时候刷新了。

例如:

这是适配器中的项目。 它将包装数据模型并公开当前状态以绑定到视图。

class ListItem(val url : String) {
    val currentProgress = MutableLiveData<Int>(0)
    val dItem = DItem(url, object : callback {
        fun onProgress(int progress) {
            currentProgress.postValue(progress)
        }
        // ...
        // Store file or error from other functions as well
    }
 }

然后,您的活动会创建这些对象(而不是 DItem)的列表,观察状态更改,并通知适配器该索引在更改时需要刷新:

class DownloadActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        val list = mutableListOf<ListItem>()
        list.add(ListItem("url").apply {
            currentProgress.observe(this@DownloadActivity) {
                // Simple implementation just refreshes the whole list when one progress changes
                // Exercise for the reader to pass along the specific index to mark as change
                adapter.notifyDataChanged()
            }
        })

然后,ViewHolder 只关心委派按钮单击事件并将视图设置为当前状态:

override fun onBindViewHolder(holder: MyViewhOdler, position: Int) {
    val listItem = list.get(position)
    holder.buttonThatTriggersDownload.setOnClickListener {
        // Set click listener to trigger download
    }
    holder.viewThatShowsDownloadProgress.value = listItem.currentProgress.value
}

评论

0赞 JSONParser 3/20/2023
因此,使用 LiveData 就像向系统添加一个回调一样。我认为它会起作用。