从回调 kotlin 中获取价值

问题描述 投票:0回答:2

尝试制作一个文件下载管理器

我们有一个包含回收站视图的活动,回收站视图中的每个项目代表一个文件,该文件处于下载或下载状态。每个回收器视图项都有一个回调,这个回调有 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 anonymous-class
2个回答
0
投票

如果我没理解错的话,你想获取“onBindViewHolder()”中的“progress”值,但你不知道该怎么做。

我想到的第一件事是:不修改太多代码但也可能是一个肮脏的解决方案:

您实际上稍后定义了您的对象回调,因此构造函数将不再接受“回调”,而是您稍后将初始化的 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
投票

我认为你的问题源于这样一个事实,即你在你的适配器中有一个具有复杂行为的domain模型列表,它应该是非常愚蠢的view模型,它只代表每个列表项的当前状态。

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
    }
 }

然后你的activity创建这些对象的列表而不是DItem,观察状态变化,当它发生变化时通知adapter那个索引需要刷新:

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
}
© www.soinside.com 2019 - 2024. All rights reserved.