本来没有这个需求,由于之前下载功能太简单,也为了多实践,业余时间实现了这个功能,经测试没有问题就合入项目代码中,现在总结下。
基本思路是开启多个下载线程,根据线程数量分段下载;本地创建RandomAccessFile文件,每个线程从文件不同位置往里写入数据,同时每次写入文件数据后把写入数据大小保存到数据库,如果下载终止需要重新开始下载从数据库中读出上次已下载的大小,从未下载的位置开始下载。
工程构成如下:
Downloader是在开始下载时创建的下载器,其中包含了N个下载线程DownloadThread,每个下载线程下载文件大小的N分之一;DownloadProgressListener是下载器的回调接口,传回每次下载后已下载的文件大小;DBOpenHelper和FileSerivce都是对数据库的操作类。下面对下载流程做详细说明:
开始下载:
创建一个Downloader对象:
path是文件url路径,dir是文件保存路径,THREAD_COUNT是线程数量。构建Downloader时会创建一个FileSerivce对象(用来操作数据库)和DownloadThread数组对象,FileSerivce会从数据库中读取之前是否下载过文件,如果不存在下载记录就新建一个表;然后将已经下载的字节数保存到一个Map表类型的对象data,key值为线程ID,value为下载字节数。开始下载,调用Downloader.download,创建多个下载线程DownloadThread:
saveFile是根据保存文件路径创建的文件,block是每个线程下载的文件大小,data.get(i+1)是每个线程已下载的文件大小,将每个线程run起来,然后到数据库保存一次:
下载中
DownloadThread会先分配每个线程下载文件的开始位置和结束位置,block是每个线程下载大小,downLength是已下载的大小:
然后创建HTTPUrlConnection,每个connection请求范围由之前的开始和结束位置决定:
然后创建随机存储文件,写入文件不同位置:
从流中读出的数据先写入一个1024字节的buffer中,每次从buffer读入数据到raf,读完一次更新一次数据库,raf文件可以指定开始写入位置,并且可以多个线程同时写入,这样就实现了多线程同时保存下载数据。