Android开发——RecyclerView实现下载列表
本篇记录的是使用Jsoup框架爬取网页内容,结合Android的RecyclerView,从而实现批量下载小说的功能(也是我的APP星之小说下载器Android版的核心功能),思路仅供参考
本文使用了AsyncTask来实现下载功能,不懂使用的可以参考一下我的文章Android开发——实现子线程更新UI
RecyclerView的使用这里也略过了,详情请看Android ListView与RecycleView的对比使用
思路分析
RecyclerView相关概念
RecyclerView的使用大家都熟悉了,我们主要继承适配器,实现了适配器中的三个方法
主要流程:
适配器获得我们写的Item.xml布局,之后根据此布局,创建了一个ViewHolder,然后,就把数据源(List存储的实体类)逐一地设置到我们写的Item.xml布局文件中(找到某个控件的实例,之后进行setText等操作)
Item进度条更新
思路:
我们的item中包含有进度条,想要实现进度条更新效果,按照之前的常理,得找到这个进度条的实例对象,然后设置进度条的进度。
问题来了——
1.如何找到进度条这个实例对象呢?
View类中提供了一个方法findViewById,通过此方法就可以找到某个实例对象,所以我们要获得进度条所在的那个root View对象(也就是itemView)
2.如何获得itemView?
RecyclerView中,提供了一个方法findViewHolderForAdapterPosition用来找到某个位置的ViewHolder,找到ViewHolder,之后就可以由此ViewHolder找到itemView
//找到特定position对应的ItemView
val itemView = rv_downloading.findViewHolderForAdapterPosition(position).itemView
val progressbar = itemView.findViewById(R.id.progress)
//kotlin中特有的自动转型功能,设置进度条进度为20
if (progressbar is ProgressBar) progressbar.progress = 20
这部分更新的UI的代码,要在AsyncTask的onProgressUpdate方法中执行(子进程中更新UI)
暂停功能
思路:
在Item的那个布局中,添加一个TextView,并设置visibility属性为gone,此TextView就是一个暂停的标记,默认text属性为1,就是不暂停。
小说下载器是是按章下载的,在开始下载某一章节的时候,检测此TextView的值是否为0,不为0则下载,为0则进入到一个死循环
当点击暂停按钮的时候,修改状态TextView的text为0即可
总结
从以上的思路分析,可以总结出这样的思路:
我们通过itemView去达到更新UI功能(上述只是简单说需要更新进度条当然,实际情况,不只更新进度条,还要更新其他的控件,具体情况,具体分析),所以需要一个List或HashMap存放itemView。
这里实际项目我选用了HashMap(名字为itemViewMap),然后HashMap的key为Int(变量名为itemPosition)表示是当前任务列表的第几个任务(从0开始),value则是该任务对应的itemView
由于我们是使用findViewHolderForAdapterPosition方法得到的ViewHolder,再由ViewHolder获得itemView对象,所以需要一个position
这里,如果考虑到任务完成之后的情况,position可能会改变,因为任务完成之后,RecyclerView会将item移出

上图中的第3个任务(即是RecyclerView中position为2的那个任务),之后RecyclerView会将该item移出列表,后面的item的position就会发生改变,原本itemPosition=3对应的position也是3,之后position发生了改变,itemPosition=3的item对应的position变为了2
由上面分析,我们应该使用一个HashMap(名字为itemPositonMap)来保存itemPosition和对应的position(itemPosition作为key,position作为value),在任务完成之后需要重新计算itemPositonMap中的映射关系(也就是在AsyncTask中的onPostExecute方法中)
由上图得到的规律:
某个任务完成了,index>该任务的index,position=position-1
每添加一个任务,新的任务的itemPosition=itemPositonMap.size,对应的position=dataList.size
itemPositionMap的长度,即是记录了当前是第几个任务
dataList即是new一个适配器传到适配器中数据源,之后任务完成需要根据position移出某个数据
实现
注意点
- ViewHolder需要在RecyclerView填充完item之后才能获取到,否则为空
- 暂停功能的那个TextView也是需要在RecyclerView填充完item之后才能获取到,否则为空
代码
private val dataList = arrayListOf<DownloadingItem>()
private val itemViewMap = hashMapOf<Int?, View>()
//itemPostion(data) - > position(recyclerview)
private val itemPositonMap = hashMapOf<Int, Int>()
internal inner class DownloadingTask : AsyncTask<String, DownloadingItem, DownloadedItem>() {
var isFirst = true
var itemPosition = 0
var tvStatus: TextView? = null
override fun onPreExecute() {
//一些初始化操作
itemPosition = itemPositonMap.size
//保存对应的item索引和位置
itemPositonMap[itemPosition] = dataList.size
}
override fun doInBackground(vararg params: String?): DownloadedItem {
val tool = NovelDownloadTool(params[0].toString(), itemPosition)
val messageItem = tool.getMessage()
publishProgress(messageItem)
for (i in 0 until tool.chacterMap.size) {
//下载每章节,并更新
val item = tool.downloadChacter(this@DownloadingFragment.activity, i)
publishProgress(item)
//tvStatus控件可能为空(因为RecyclerView的itemView未初始化成功)
while (tvStatus?.text.toString() != "1") {
}
// if (tvStatus != null) while (tvStatus!!.text.toString() != "1"){}
}
//合并文件,并返回一个数据类(DownloadedItem),之后添加到另外的RecyclerView中
return tool.mergeFile(this@DownloadingFragment.activity)
}
override fun onProgressUpdate(vararg values: DownloadingItem?) {
//recyclerView Item更新
if (isFirst) {
values[0]?.let { dataList.add(it) }
adapter?.notifyDataSetChanged()
isFirst = false
} else {
if (tvStatus == null) {
val itemView = rv_downloading.findViewHolderForAdapterPosition(itemPositonMap[itemPosition] as Int).itemView
tvStatus = itemView.findViewById(R.id.tv_status) as TextView?
//存入itemView
itemViewMap[values.last()?.itemPosition] = itemView
}
updateItem(values.last())
}
}
override fun onPostExecute(result: DownloadedItem?) {
showToast("下载成功")
//移出adapter中的数据
val position = itemPositonMap[result?.itemPosition] as Int
adapter?.notifyItemRemoved(position)
dataList.removeAt(position)
//下载完成,重新计算itemPostion对应的position
for (i in position + 1 until itemPositonMap.size) {
itemPositonMap[i] = itemPositonMap[i] as Int - 1
}
val mainactivity = this@DownloadingFragment.activity as MainActivity
mainactivity.addItemToHistory(result)
}
}
缺点
- itemPositonMap和itemViewMap在任务列表存在过多任务,占用的内存会过大(可以考虑在任务列表任务全部完成之后进行一次清空操作)
- 暂停功能使用的是while死循环,可能会产生bug
Android开发——RecyclerView实现下载列表的更多相关文章
- android 开发 RecyclerView 横排列列表布局
1.写一个一竖的自定义布局: <?xml version="1.0" encoding="utf-8"?> <LinearLayout xml ...
- Android开发——RecyclerView特性以及基本使用方法(二)
0. 前言 随着Android的发展,虽然ListView依旧重要,但RecyclerView确实越来越多的被大家使用.但显然并不能说RecyclerView就一定优于ListView,而是应该根据 ...
- Android开发——RecyclerView特性以及基本使用方法(一)
)关于点击事件,没有像ListView那样现成的API,但是自己封装起来也不难,而且我们使用ListView时,如果item中有可点击组件,那么点击事件的冲突也是一个问题,而在RecyclerView ...
- Android开发调试常用命令列表
Android开发调试常用命令列表 adb命令 am am start -n com.iflytek.autofly.account/.ui.MainActivity am start -n com. ...
- 10本最新的Android开发电子书免费下载
最新的Android开发电子书大集合,免费下载! 1.The Business of Android Apps Development, 2nd Edition http://ebook.goodfa ...
- Android开发系列----sdk下载 环境准备
今天开始准备Android开发环境,FQ下载Android Studio,官网下载地址 https://developer.android.com/studio/install.html (突然发现我 ...
- Android开发----RecyclerView视图的学习
RecyclerView RecyclerView是什么? RecyclerView是如今Android开发中最常用的控件,其相较于ListView和GridView的功能更为强大,优化了两者的各种不 ...
- Android开发多线程断点续传下载器
使用多线程断点续传下载器在下载的时候多个线程并发可以占用服务器端更多资源,从而加快下载速度,在下载过程中记录每个线程已拷贝数据的数量,如果下载中断,比如无信号断线.电量不足等情况下,这就需要使用到断点 ...
- android开发 RecyclerView 瀑布列表布局
1.写一个内容的自定义小布局: <?xml version="1.0" encoding="utf-8"?> <LinearLayout xm ...
随机推荐
- 【Offer】[62] 【圆圈中最后剩下的数字】
题目描述 思路分析 测试用例 Java代码 代码链接 题目描述 0,1,,n-1这n个数字排成一个圆圈,从数字0开始,每次从这个圆圈里删除第m个数字.求出这个圆圈里剩下的最后一个数字. 牛客网刷题地址 ...
- AWGN
高斯白噪声的功率谱密度服从均匀分布,幅度分布服从高斯分布: 白噪声是指它的二阶矩不相关,一阶矩为常数,是指先后信号在时间上的相关性: 高斯白噪声在任意两个不同时刻上的随机变量之间,不仅是互不相关的,而 ...
- 微软发布.Net Core 3.0 RC1,最终版本定于9月23日
2019.9.17 微软 宣布推出.NET Core 3.0 Release Candidate 1.就像Preview 9一样,主要专注于为 .NET Core 3.0 发布最终版本 .现在变得非常 ...
- ubuntu下配置JDK,Eclipse,android开发环境
前言:由于我的电脑是64位的,所以下面使用的jdk ; eclipse : 包括我安装的 ubuntu12.0.4LTS 都是64位的:如果你是32位请下载32位的系统以及jdk,eclipse等软件 ...
- Jackson 序列化和反序列化
博客地址:https://www.moonxy.com 一.前言 Jackson 功能很强大,既能满足简单的序列化和反序列化操作,也能实现复杂的.个性化的序列化和反序列化操作.到目前为止,Jackso ...
- CentOS7 安装 Pure-ftpd
博客地址:http://www.moonxy.com 一.摘要 FTP 是 File Transfer Protocol(文件传输协议)的英文简称,而中文简称为"文传协议”.用于Intern ...
- [AI] 深度数据 - Data
Data Engineering Data Pipeline Outline [DE] How to learn Big Data[了解大数据] [DE] Pipeline for Data Eng ...
- 如何判断前后端bug
测试工程师不只是负责发现问题,除了发现问题这种基本功外,定位问题,提出解决方案,提出预防方案也是要掌握的技能.这里先说定位问题的要求,定位问题要向深入,前提当然是对功能.产品的流程.开发方案.开发人员 ...
- Salem and Sticks-萨鲁曼的棍子 CodeForce#1105A 暴力
题目链接:Salem and Sticks 题目原文 Salem gave you
- TCP/IP 物理层卷一 -- 基本概念
一.基本概念: 物理层:TCP/IP 协议簇的最底层,物理层所需要考虑的是如何在连接计算机的传输媒体上传输数据的比特流,而不是连接计算机的具体物理设备. 信号:数据的电气或电磁表现,是数据在传输媒体上 ...