从广播接收器更新 Recyclerview 中的进度条

Update Progressbar in Recyclerview from Broadcast Receiver

我正在尝试弄清楚如何在收到接收方的进度更新后更新特定项目的进度条。

这是我在片段中的接收器:

private val mReceiver = object : BroadcastReceiver() {
        override fun onReceive(context: Context, intent: Intent) {
            when(intent.action) {
                PROGRESS_UPDATE_ACTION -> {
                    val resId = intent.extras.getInt("resourceID")
                    val progress = intent.extras.getInt("contentLength$resId")
                    val maxProgress = intent.extras.getLong("maxProgress$resId")
                    adapter.update(resId, progress, maxProgress)
                }
            }
        }
    }

适配器是从数据库中填充的。每个项目都有一个唯一的 resourceID。

private fun loadDataFromBox(){
        val query = SaveOfflineManager().getAll()
        val saveOfflineData = LinkedHashMap<Int, SaveOfflineData>()
        query.forEach {
            saveOfflineData[it.resourceID!!] = it
        }

        adapter.setData(saveOfflineData)
        adapter.notifyDataSetChanged()
    }

这是我的简化适配器。如您所见,我不知道如何处理从接收器接收更新的方法。我尝试搜索解决方案数小时,但似乎找不到任何解决方案。

class SaveOfflineAdapter : RecyclerView.Adapter<SaveOfflineAdapter.SimpleViewHolder>() {

    private var downloadMap : LinkedHashMap<Int, SaveOfflineData> = LinkedHashMap()
    private var utils : Utils = Utils()


    fun setData(downloadist : LinkedHashMap<Int, SaveOfflineData>) {
        this.downloadMap.clear()
        this.downloadMap = downloadist
        this.notifyDataSetChanged()
    }

    fun update(resourceID : Int, progress : Int, maxProgress : Long) {
        // update progress for a specific resourceID
        // what to do here?
        this.notifyDataSetChanged() // makes app real slow when called repeatedly
    }

    override fun getItemCount(): Int {
        return downloadMap.count()
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SimpleViewHolder {
        val view = LayoutInflater.from(parent.context).inflate(R.layout.save_offline_container_layout, parent, false)
        return SimpleViewHolder(view)
    }

    override fun onBindViewHolder(holder: SimpleViewHolder, position: Int) {

        holder.savedData = ArrayList(downloadMap.values)[position]

        if (ArrayList(downloadMap.values)[position].status == "Completed") {
            holder.downloadProgress?.visibility = View.INVISIBLE
        } else {
            holder.downloadProgress?.visibility = View.VISIBLE
//            update progress here??
//            holder.downloadProgress.progress = holder.savedData.progress!!
//            holder.downloadProgress.max = holder.savedData.totalContentLength!!
        }
    }

    inner class SimpleViewHolder(v: View, var savedData: SaveOfflineData? = null) : RecyclerView.ViewHolder(v) {
        var downloadProgress : ProgressBar? = v.findViewById(R.id.saveOffProgress)

    }

}

简化片段代码:

class SaveOfflineFragment: BaseFragment(), View.OnClickListener{

    var adapter = SaveOfflineAdapter()
    var tabKey = 0

    private var saveOfflineRecyclerView : RecyclerView?       = null

    private val mReceiver = object : BroadcastReceiver() {
        override fun onReceive(context: Context, intent: Intent) {
            when(intent.action) {
                PROGRESS_UPDATE_ACTION -> {
                    val resId = intent.extras.getInt("resourceID")
                    val progress = intent.extras.getInt("contentLength$resId")
                    val maxProgress = intent.extras.getLong("maxProgress$resId")
                    adapter.update(resId, progress, maxProgress)

                }
                DOWNLOAD_DONE_ACTION -> {
                    loadDataFromBox()
                }

            }

        }
    }


    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        rootView = inflater.inflate(R.layout.saveoffline_layout, container, false)
        activity!!.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
        ScreenTracking.getInstance().track(TAG_SAVE_OFFLINE_FRAG + tabKey, false)

        getViews()
        setIds()
        setViews()

        return rootView
    }

    private fun getViews() {
        saveOfflineRecyclerView  = rootView!!.recyclerview_main
    }

    private fun setIds(){
        val idRecyclerView: IntArray = intArrayOf(R.id.saveOfflineRecyclerView1, R.id.saveOfflineRecyclerView2, R.id.saveOfflineRecyclerView3, R.id.saveOfflineRecyclerView4)

        val position = tabKey - 1
        saveOfflineRecyclerView!!.id  = idRecyclerView [position]
    }

    private fun setViews(){
        saveOfflineRecyclerView!!.layoutManager = LinearLayoutManager(activity, LinearLayoutManager.VERTICAL, false)
        saveOfflineRecyclerView!!.layoutManager!!.isItemPrefetchEnabled = true
        saveOfflineRecyclerView!!.isNestedScrollingEnabled = false
        saveOfflineRecyclerView!!.setHasFixedSize(true)
        saveOfflineRecyclerView!!.setItemViewCacheSize(20)
        saveOfflineRecyclerView!!.isDrawingCacheEnabled = true
        saveOfflineRecyclerView!!.drawingCacheQuality = View.DRAWING_CACHE_QUALITY_HIGH
        adapter.hasStableIds()
        saveOfflineRecyclerView!!.adapter = adapter
    }

    override fun onClick(v: View?) {
        when (v!!.id) {
            R.id.saveOfflineSearchBtn1, R.id.saveOfflineSearchBtn2, R.id.saveOfflineSearchBtn3, R.id.saveOfflineSearchBtn4 -> {

            }

            R.id.confirmDeleteCancel -> {

            }

            R.id.confirmDeleteYes -> {

            }

        }
    }

    override fun onResume() {
        println("On resume, registering receiver")
        super.onResume()

        val mIntentFilter = IntentFilter()
        mIntentFilter.addAction(PROGRESS_UPDATE_ACTION)
        mIntentFilter.addAction(DOWNLOAD_DONE_ACTION)
        BuriIOApp.context.registerReceiver(mReceiver, mIntentFilter)
    }

    override fun onPause() {
        println("onpause unregistering receiver")
        BuriIOApp.context.unregisterReceiver(mReceiver)
        super.onPause()
    }

    override fun onAttach(context: Context?) {
        super.onAttach(context)
        tabKey = arguments!!.getInt("tabKey")
        fragmentCallback = context as FragmentCallback
        loadDataFromBox()
    }

    private fun loadDataFromBox(){
        val query = SaveOfflineManager().getAll()
        val saveOfflineData = LinkedHashMap<Int, SaveOfflineData>()
        query.forEach {
            saveOfflineData[it.resourceID!!] = it
        }
        adapter.setData(saveOfflineData)
        adapter.notifyDataSetChanged()


    }

    companion object {
        fun newInstance(tabKey : Int): SaveOfflineFragment {
            val args = Bundle()
            args.putInt("tabKey", tabKey)
            val fragment = SaveOfflineFragment()
            fragment.arguments = args
            return fragment

        }
    }

}

update 方法中,您必须找到更新的项目,并将最后的更改应用到该项目。像这样:

fun update(resourceID : Int, progress : Int, maxProgress : Long) {
    if (downloadMap.get(resourceID)!=null) {
        downloadMap.get(resourceID).progress = progress
        downloadMap.get(resourceID).totalContentLength = maxProgress
    }
    this.notifyDataSetChanged() // makes app real slow when called repeatedly
}

然后在 onBindViewHolder 方法中,您必须处理进度状态,例如:

Override fun onBindViewHolder(holder: SimpleViewHolder, position: Int) {

    holder.savedData = ArrayList(downloadMap.values)[position]

    if (ArrayList(downloadMap.values)[position].status == "Completed") {
        holder.downloadProgress?.visibility = View.INVISIBLE
    } else {
        holder.downloadProgress?.visibility = View.VISIBLE 
        holder.downloadProgress.progress = holder.savedData.progress!!
        holder.downloadProgress.max = holder.savedData.totalContentLength!!
    }
}

提示:在update方法中你可以使用notifyItemChanged代替notifyDataSetChanged。这只是反弹一项并且有更好的表现。见下文:

fun update(resourceID : Int, progress : Int, maxProgress : Long) {
    val data = downloadMap.get(resourceID)
    if (data!=null) {
        data.progress = progress
        data.totalContentLength = maxProgress
        val index = ArrayList(downloadMap.values).indexOf(data)
        this.notifyItemChanged(index) 
    }
}