在 Android 的 Recyclerview 中显示下载进度

     2023-05-07     24

关键词:

【中文标题】在 Android 的 Recyclerview 中显示下载进度【英文标题】:Show Download progress in a Recyclerview in Android 【发布时间】:2018-08-07 03:56:09 【问题描述】:

我目前正在开发可以下载视频文件的应用程序。我正在使用下载管理器下载文件,一切正常,因为文件正在正确下载,我可以在通知中看到下载进度。现在我想在另一个类(包含recyclerview)中显示那些下载文件的进度。那么我应该怎么做才能实现这个模块呢?

  String urlDownload = mUrl;
        String filename = mUrl.substring(mUrl.lastIndexOf('/') + 1);
        Log.i("onLoadResource()", "url = " + mUrl + "\n" + filename);
        DownloadManager.Request request = new DownloadManager.Request(Uri.parse(urlDownload));

    request.setDescription("Testando");
    request.setTitle("Download");
    request.allowScanningByMediaScanner();
    request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
    request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, filename);

    final DownloadManager manager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE);

    final long downloadId = manager.enqueue(request);

    final ProgressBar mProgressBar = (ProgressBar) findViewById(R.id.progress_bar);

    new Thread(new Runnable() 

        @Override
        public void run() 

            boolean downloading = true;

            while (downloading) 

                DownloadManager.Query q = new DownloadManager.Query();
                q.setFilterById(downloadId);

                Cursor cursor = manager.query(q);
                cursor.moveToFirst();
                int bytes_downloaded = cursor.getInt(cursor
                        .getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR));
                int bytes_total = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_TOTAL_SIZE_BYTES));

                if (cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS)) == DownloadManager.STATUS_SUCCESSFUL) 
                    downloading = false;
                

                final int dl_progress = (int) ((double)bytes_downloaded / (double)bytes_total * 100f);

                runOnUiThread(new Runnable() 

                    @Override
                    public void run() 

                        mProgressBar.setProgress((int) dl_progress);

                    
                );


                cursor.close();
            

        
    ).start();

【问题讨论】:

只是将下载百分比广播到该类..并更新该活动中回收者的进度条 好的,我明白了,谢谢,但是如何在 recyclerview 适配器中添加多个文件请给我一些指导 如何在该课程中设置广播下载百分比请指导我 我有这个问题超过 1.5 年。 *** 中没有人回答这个话题。甚至,谷歌也帮不上忙 我遇到了同样的问题。你解决了吗? 【参考方案1】:

在您为每个 RecyclerViewItem 使用的数据模型中维护一个变量用于进度。当您收到有关进度的更新时,请更新您正在使用的数据集,然后调用 notifyItemChanged(mPos)notifyItemRangeChanged() 以通知适配器。 notifyItemChanged(mPos) 触发 onBindVieHolder 对应的位置,即使它当前不可见。

【讨论】:

【参考方案2】:

以下是一些一般性建议。

您可以通过调用notifyItemRangeChanged(int positionStart, int itemCount, Object payload) 来更新RecyclerView 行。这将在您的适配器中调用onBindViewHolder(FeedBaseViewHolder holder, int position, List<Object> payloads),您可以在其中使用进度条更新一行。

在有效负载中,您可以将所需值的角度与您的要求一起传递,例如开始进度操作、更新进度、停止进度。

希望对你有帮助。

【讨论】:

【参考方案3】:

之前建议使用notifyItemChanged() 的答案给了我三个大问题:

    它不必要地更新整个 ViewHolder 和所有子视图, 当您在显示更新的同时滚动列表时,它会产生无穷无尽的烦人动画 它显示随机(不值得/不正确的)ViewHolders 的进度更新

为我解决所有这些问题的方法是使用回调来更新与进度相关的特定视图。我的解决方案是在 Kotlin 中,因为 A) 这就是我所做的,B) 它是为了让这些问题变得简单,C) OP 没有将 Java 指定为语言。

PRDownload 库通过在每个响应/更新时调用的内置回调系统使这更容易一些 - 这是DownloadManager 所没有的。要使用DownloadManager,您只需创建一个计时器(可能是WorkManager)来查询DownloadManager 数据库并定期获取下载进度,并根据进度调用回调。

PRDownload 的依赖:
implementation "com.mindorks.android:prdownloader:0.6.0"

适配器

import android.os.Handler
import android.os.Looper
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.downloader.Error
import com.downloader.OnDownloadListener
import com.downloader.OnProgressListener
import com.downloader.PRDownloader
import com.downloader.Progress

val mutableMapOfIDToProgressListenerCallback: MutableMap<Int, MyDownloadProgressListener> =
    mutableMapOf()

class RecyclerViewAdapter(private val dataSet: List<ListItem>) :
    RecyclerView.Adapter<RecyclerViewAdapter.ViewHolder>() 

    inner class ViewHolder(view: View) : RecyclerView.ViewHolder(view) 
        lateinit var listItem: ListItem
        val percentDownloaded = itemView.findViewById<TextView?>(R.id.percent_downloaded)
        fun setUpdateViewLambda() 
            mutableMapOfIDToProgressListenerCallback[listItem.id]?.setLabmda 
                percentDownloaded?.text = toPercent(it).toString()
            
        

        fun removeUpdateViewLambda() 
            mutableMapOfIDToProgressListenerCallback[listItem.id]?.setLabmda 
        

        init 
            view.setOnClickListener  //to demonstrate downloads
                Thread  //use coroutines instead
                        downloadItem(
                            listItem,
                            adapterPosition,
                            this@RecyclerViewAdapter,
                            "https://downloads.gradle-dn.com/distributions/gradle-6.9.1-bin.zip", //insert your download here
                            view.context.getExternalFilesDir(null)!!.absolutePath,
                            "a$listItem.id.zip"
                        )
                .start()
            
        
    

    override fun onViewAttachedToWindow(holder: ViewHolder) 
        holder.setUpdateViewLambda()
        super.onViewAttachedToWindow(holder)
    

    override fun onViewDetachedFromWindow(holder: ViewHolder) 
        holder.removeUpdateViewLambda() //remove callback so that recycled viewholder doesn't undeservingly get updates
        super.onViewDetachedFromWindow(holder)
    

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder 
        return ViewHolder(
            LayoutInflater
                .from(parent.context)
                .inflate(R.layout.list_item, parent, false)
        )
    

    override fun onBindViewHolder(holder: ViewHolder, position: Int) 
        val listItem = dataSet[position]

        //perform your binding

        holder.listItem = listItem
        holder.percentDownloaded?.text = listItem.percentDownloaded.toString()
        holder.setUpdateViewLambda()
    

    override fun getItemCount(): Int 
        return dataSet.size
    


data class ListItem(
    val id: Int, //a value that uniquely represents this list item
    var percentDownloaded: Byte //can only ever be between 0-100, so no need for Int
)

class MyDownloadProgressListener : OnProgressListener 
    lateinit var listItem: ListItem
    private var updateView: (progress: Progress) -> Unit = 
    fun setLabmda(lambda: (progress: Progress) -> Unit) 
        updateView = lambda
    

    override fun onProgress(progress: Progress?) 
        Log.d("Adapter", "Progress object: $progress")
        if (progress != null) 
            val toPercent = toPercent(progress)
            Log.d("Adapter", "Percent received: $toPercent")
            listItem.percentDownloaded = toPercent
            updateView(progress)
        
    


fun downloadItem(
    listItem: ListItem,
    adapterPosition: Int,
    adapter: RecyclerViewAdapter,
    url: String,
    dirPath: String,
    filename: String
) 
    val listener = MyDownloadProgressListener()
    mutableMapOfIDToProgressListenerCallback[listItem.id] = listener
    listener.listItem = listItem
    Handler(Looper.getMainLooper()).post  adapter.notifyItemChanged(adapterPosition)/*bind listener to ViewHolder*/ 

    PRDownloader
        .download(url, dirPath, filename)
        .build()
        .setOnProgressListener(listener)
        .setOnCancelListener 
                mutableMapOfIDToProgressListenerCallback.remove(listItem.id)
        
        .start(object : OnDownloadListener 
            override fun onDownloadComplete() 
                mutableMapOfIDToProgressListenerCallback.remove(listItem.id)
            

            override fun onError(error: Error?) 
                mutableMapOfIDToProgressListenerCallback.remove(listItem.id)
            
        
    )


fun toPercent(progress: Progress) =
    (100 * (progress.currentBytes / progress.totalBytes.toDouble())).toInt().toByte()

【讨论】:

Android:在recyclerview下方显示按钮,但始终在屏幕上

】Android:在recyclerview下方显示按钮,但始终在屏幕上【英文标题】:Android:Showbuttonjustbelowtotherecylerviewbutalwaysonthescreen【发布时间】:2021-11-2111:36:30【问题描述】:在屏幕上,我想显示从顶部开始的RecyclerView,在RecyclerView的末尾... 查看详情

在recyclerview项目android中更改视图之间的焦点

】在recyclerview项目android中更改视图之间的焦点【英文标题】:Changingfocusbetweenviewsinrecyclerviewitemandroid【发布时间】:2020-10-3104:45:57【问题描述】:我正在为AndroidTV改编我的应用。我有带有项目的RecyclerView。每个项目包含三个Linear... 查看详情

在 RecyclerView 中获取一行的宽度和高度 - Android

】在RecyclerView中获取一行的宽度和高度-Android【英文标题】:GetWidthandHeightofonerowinRecycleView-Android【发布时间】:2015-09-1814:15:12【问题描述】:我正在用一些项目创建RecycleView。所以需要得到RecycleView这一行的宽高我在这里创建Recyc... 查看详情

Android:在 Recyclerview 中更改图像旋转

】Android:在Recyclerview中更改图像旋转【英文标题】:Android:changingimagerotationinsideRecyclerview【发布时间】:2022-01-1005:24:07【问题描述】:我有一个显示来自firebase的图像的recyclerView,由于某种原因,其中一些图像在上传到firenase时... 查看详情

在 Android 的 Recyclerview 中显示下载进度

】在Android的Recyclerview中显示下载进度【英文标题】:ShowDownloadprogressinaRecyclerviewinAndroid【发布时间】:2018-08-0703:56:09【问题描述】:我目前正在开发可以下载视频文件的应用程序。我正在使用下载管理器下载文件,一切正常,因... 查看详情

如何在 Android 的 RecyclerView 中显示来自 Firestore 的数据?

】如何在Android的RecyclerView中显示来自Firestore的数据?【英文标题】:HowtodisplaydatafromFirestoreinaRecyclerViewwithAndroid?【发布时间】:2018-08-2223:39:33【问题描述】:使用Android在RecyclerView中显示现有Firestore数据库中的数据的最佳方式是... 查看详情

Android - 在 RecyclerView 中滚动时颜色重复

】Android-在RecyclerView中滚动时颜色重复【英文标题】:Android-ColorrepeatonscrollinginRecyclerView【发布时间】:2020-09-3007:19:35【问题描述】:我有一个RecyclerView,其中选定数量的项目显示不同的背景颜色。它给了我很多不同颜色的视图... 查看详情

如何在android中排列RecyclerView上的数据?

】如何在android中排列RecyclerView上的数据?【英文标题】:HowtoarrangethedataonRecycleViewinandroid?【发布时间】:2016-12-2706:33:33【问题描述】:我想使用RecycleView来显示我的数据数组。这是我的Adapater类,它在视图上设置数据。publicclassDa... 查看详情

如何在android中删除Recyclerview项目之间的分隔符

】如何在android中删除Recyclerview项目之间的分隔符【英文标题】:howtoremovedividerbetweenitemsofRecyclerviewinandroid【发布时间】:2016-03-0909:32:21【问题描述】:我想删除RecyclerView项目之间的分隔符(空格)所以尝试将项目视图的background... 查看详情

Android - 滑动以在背景上关闭带有动画的 RecyclerView

】Android-滑动以在背景上关闭带有动画的RecyclerView【英文标题】:Android-SwipetodismissRecyclerViewwithanimationonthebackground【发布时间】:2018-01-1721:03:10【问题描述】:据我了解,为RecyclerView实现滑动关闭的一种可能性是在滑动项目下方... 查看详情

Android - 在 RecyclerView 中单击的项目上打开新活动 [重复]

】Android-在RecyclerView中单击的项目上打开新活动[重复]【英文标题】:Android-OpennewactivityonitemclickedinRecyclerView[duplicate]【发布时间】:2018-02-0422:13:37【问题描述】:我正在为新手创建一个简单的应用程序,但我被困在主要部分。我... 查看详情

如何在android的recyclerview中搜索数据

】如何在android的recyclerview中搜索数据【英文标题】:Howtosearchdatainrecylerviewinandroid【发布时间】:2020-04-2723:57:22【问题描述】:我的所有代码都运行成功,但我想添加Searchview。我尝试了很多方法。edittext文本更改应用程序崩溃时... 查看详情

如何在 Android Studio 中禁用 recyclerview 特定数据?

】如何在AndroidStudio中禁用recyclerview特定数据?【英文标题】:HowcanIdisablerecyclerviewparticulardatainAndroidstudio?【发布时间】:2021-12-1008:01:40【问题描述】:在数据库中新的时间戳1:aaa时间戳2:bbb此数据将被10个用户读取,每当有新数据... 查看详情

Android使用gridlayoutmanager在recyclerview中的最后一个元素下方添加间距

】Android使用gridlayoutmanager在recyclerview中的最后一个元素下方添加间距【英文标题】:Androidaddspacingbelowlastelementinrecyclerviewwithgridlayoutmanager【发布时间】:2015-09-0104:25:48【问题描述】:我正在尝试使用GridLayoutManager在RecyclerView的最... 查看详情

在android RecyclerView中同时设置两个项目的颜色

】在androidRecyclerView中同时设置两个项目的颜色【英文标题】:SettwoitemscoloratsametimeinandroidRecyclerView【发布时间】:2021-09-1819:42:53【问题描述】:我需要根据用户的选择同时更改两个recylerview项目的颜色。例如:-我们在recyclerview中... 查看详情

Android - 网格中项目之间的 RecyclerView 间距

】Android-网格中项目之间的RecyclerView间距【英文标题】:Android-RecyclerViewspacingbetweenitemsinaGrid【发布时间】:2015-10-0802:45:43【问题描述】:在我的Android应用程序中,我使用RecyclerView在网格中显示项目,方法是使用GridLayoutManager。在... 查看详情

RecyclerView 不能在 cardview 上正确显示数据(Android)?

】RecyclerView不能在cardview上正确显示数据(Android)?【英文标题】:RecyclerViewnotdisplayingdataoncardviewproperly(Android)?【发布时间】:2016-10-2916:29:11【问题描述】:我正在制作一个文件管理器,我正在尝试使用RecyclerView。问题是recyclerv... 查看详情

我们如何在 android 的 RecyclerView 片段中使用 bottomSheet?

】我们如何在android的RecyclerView片段中使用bottomSheet?【英文标题】:HowwecanusebottomSheetinfragmentforRecyclerViewinandroid?【发布时间】:2022-01-1520:05:04【问题描述】:我有一个简单的项目,我想在片段中使用底部表作为列表项,一切看起... 查看详情