简体   繁体   中英

Update Progressbar in Recyclerview from Broadcast Receiver

I'm trying to figure out how to update a specific item's progressbar upon receiving the progress update from the receiver.

This is my receiver in a fragment:

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

The adapter is populated from a database. Each item has a unique resourceID.

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

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

And this is my simplified adapter. As you can see, I have no idea what to do with the method that receives the update from the receiver. I tried searching for solutions for hours but can't seem to find any.

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)

    }

}

simplified fragment code:

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

        }
    }

}

In the update method you must find which item is updated, and apply the last changes to that item. something like this:

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
}

And after that in the onBindViewHolder method, you must handle the progress status, something like:

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

HINT : In the update method you can use notifyItemChanged instead of notifyDataSetChanged . this is rebound only one item and have better performance. see below:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM