Android原生实现多线程断点下载实例代码
程序员文章站
2023-12-10 19:20:04
各位父老乡亲,我单汉三又回来了,今天为大家带来一个用原生的安卓写的多线程断点下载demo。
通过本文你可以学习到:
sqlite的基本使用,数据库的增删改查。...
各位父老乡亲,我单汉三又回来了,今天为大家带来一个用原生的安卓写的多线程断点下载demo。
通过本文你可以学习到:
- sqlite的基本使用,数据库的增删改查。
- handler的消息处理与更新ui。
- service(主要用于下载)的进阶与使用。
- 原生的json文件解析(多层嵌套)。
- randomaccessfile的基本使用,可以将文件分段。
- 基于httpurlconnection的大文件下载。
- 上面内容结合,实现多线程,断点下载。
demo是在tv上运行的,图片显示的问题不要纠结了。
文件下载的demo已完成,没时间上传与讲解,今天为您展示并讲解一下,纯原生的东西来下载文件,希望可以帮你理解更多安卓比较基础的问题。
我们的思路:建立一个数据库,两个表,一个用来保存网络数据,一个保存本地下载的进度等等。在点击下载按钮的时候启动downloadservice,进行比对之后下载
先看一下demo的目录结构:
所有的步骤在代码里有非常详细的讲解,一定要看代码(下面是抽取的几个重要的类讲解)!
数据库的建立与dao
/** * created by administrator on 2017/3/6 0006. */ public class downloaddbhelper extends sqliteopenhelper { /** * downloaddbhelper用于创建数据库,如果不会使用原生的建库的话 * * 跟随小司机我的脚步来一起练一练 * 建两个表: * download_info表存储下载信息 * localdownload_info表存储本地下载信息 * 之后对比两个表进行继续下载等等 */ public static string database_name = "downloadfiles.db"; public static string table_download_info = "download_info"; public static string table_localdownload_info = "localdownload_info"; private static int version = 1; public downloaddbhelper(context context) { super(context, database_name, null, version); } @override public void oncreate(sqlitedatabase db) { /*在此进行创建数据库和表格,来一起动手写一遍,就是两个sqlite语句*/ db.execsql("create table " + table_download_info + "(" + "id integer primary key autoincrement," + "thread_id integer," + "start_position integer," + "end_position integer," + " completed_size integer," + "url varchar(100))"); db.execsql("create table " + table_localdownload_info + "(" + "id integer primary key autoincrement," + "name varchar(50)," + "url varchar(100)," + "completedsize integer," + "filesize integer," + "status integer)"); } @override public void onupgrade(sqlitedatabase db, int oldversion, int newversion) { /*数据库更新升级,检测到版本的变化,发现版本号不一样,就会自动调用onupgrade函数 * 新版本号和老版本号都会作为onupgrade函数的参数传进来,便于开发者知道数据库应该从哪个版本升级到哪个版本。 * */ string sql = "drop table if exists " + table_download_info + ""; string sqlone = "drop table if exists " + table_localdownload_info + ""; db.execsql(sql); db.execsql(sqlone); oncreate(db);//删除数据库,重新创建。这里只是简单的,并没有添加或者减少数据库中的其他字段 } }
dao对数据库进行增删改查
/** * created by shancancan on 2017/3/6 0006. */ public class dao { /* * dao层主要是做数据持久层的工作,负责与数据库进行联络的一些任务都封装在此。 * dao层所定义的接口里的方法都大同小异,这是由我们在dao层对数据库访问的操作来决定的, * 对数据库的操作,我们基本要用到的就是新增,更新,删除,查询等方法。 * 因而dao层里面基本上都应该要涵盖这些方法对应的操作。 * */ private static dao dao; private static downloaddbhelper dbhelper; public static final byte[] lock = new byte[0]; //新建两个字节作为对象锁 public static final byte[] file_lock = new byte[0]; public dao() {//空构造方法, } public static synchronized dao getinstance(context context) {//本demo用单例模式中的懒汉模式+线程不安全 线程安全的代价是效率变低 if (dao == null) { dao = new dao(); dbhelper = new downloaddbhelper(context); } return dao; } /* public static synchronized dao getinstance(context context) {//本demo用单例模式中的懒汉模式+线程安全 线程安全的代价是效率变低,99%情况下不需要同步 if (dao == null) { //你可以在这两个方法中随便选择一个 dao = new dao(); dbhelper = new downloaddbhelper(context); } return dao; }*/ /*************************************** 下方dao层中对数据库的增、删、改、查 *********************************************************/ /** * 检查本地下载记录,是否下载过 * * @param url * @return */ public boolean isexist(string url) { sqlitedatabase database = dbhelper.getreadabledatabase(); //获取本app所创建的数据库 string sql = "select count(*) from " + table_localdownload_info + " where url=?"; //查询语句,查询总共有多少条的语句 cursor cursor = database.rawquery(sql, new string[]{url}); /** * * @cursor * cursor 是每行的集合。 * 使用 movetofirst() 定位第一行。 * 你必须知道每一列的名称。 * 你必须知道每一列的数据类型。 * cursor 是一个随机的数据源。 * 所有的数据都是通过下标取得。 * cursor按照我的理解就是一个箭头,指到哪一行就是那一行的集合 * 比较重要的方法有:close(),movetofirst(),movetonext(),movetolast(),movetoprevious(),getcolumncount()等。 * * @rawquery * rawquery是直接使用sql语句进行查询的,也就是第一个参数字符串, * 在字符串内的“?”会被后面的string[]数组逐一对换掉 * cursor用完之后要关闭,cursor用完之后要关闭,cursor用完之后要关闭。重要的事情说三遍!!! * * */ cursor.movetofirst(); int count = cursor.getint(0); cursor.close(); return count > 0; } /** * 是否为首次下载 * * @param url * @return */ public boolean isfirstdownload(string url) { sqlitedatabase database = dbhelper.getreadabledatabase(); string sql = "select count(*) from " + table_download_info + " where url=?"; cursor cursor = database.rawquery(sql, new string[]{url}); cursor.movetofirst(); int count = cursor.getint(0); cursor.close(); return count == 0; } /** * 保存下载的具体信息 保存所下载的list集合中的数据 * * @param infos * @param context */ public void saveinfos(list<downloadinfo> infos, context context) { /** * 事务(transaction)是并发控制的单位,是用户定义的一个操作序列。 * 这些操作要么都做,要么都不做,是一个不可分割的工作单位。 * 通过事务,sql server能将逻辑相关的一组操作绑定在一起, * 以便保持数据的完整性。 * * 事务具有四个特征:原子性( atomicity )、一致性( consistency )、 * 隔离性( isolation )和持续性( durability )。这四个特性简称为 acid 特性。 * * */ synchronized (lock) { sqlitedatabase database = dbhelper.getwritabledatabase(); database.begintransaction();//开启事务 try {//如果有异常,在这里捕获 for (downloadinfo info : infos) {//for循环将数据存入数据库 string sql = "insert into " + table_download_info + "(thread_id,start_position, end_position, completed_size, url) values (?,?,?,?,?)"; object[] bindargs = {info.getthreadid(), info.getstartposition(), info.getendposition(), info.getcompletedsize(), info.geturl()}; database.execsql(sql, bindargs); } database.settransactionsuccessful();//结束事务 } catch (sqlexception e) { e.printstacktrace(); } finally { database.endtransaction();//关闭事务 } } } /** * 得到下载具体信息 * * @param urlstr * @return list<downloadinfo> 一个下载器信息集合器,里面存放了每条线程的下载信息 */ public list<downloadinfo> getinfos(string urlstr) { list<downloadinfo> list = new arraylist<downloadinfo>(); sqlitedatabase database = dbhelper.getreadabledatabase(); string sql = "select thread_id, start_position, end_position, completed_size, url from " + table_download_info + " where url=?"; cursor cursor = database.rawquery(sql, new string[]{urlstr}); while (cursor.movetonext()) {//通过cursor取到下载器信息,循环遍历,得到下载器集合 downloadinfo info = new downloadinfo(cursor.getint(0), cursor.getint(1), cursor.getint(2), cursor.getint(3), cursor.getstring(4)); list.add(info); } cursor.close(); return list; } /** * 本地下载列表添加记录,添加本地数据库信息,完成度等等 * * @param filestatus **/ public void insertfilestatus(filestatus filestatus) { synchronized (file_lock) {//异步加开启事务,保证数据的完整性 sqlitedatabase database = dbhelper.getwritabledatabase(); database.begintransaction(); try { string sql = "insert into " + table_localdownload_info + " (name,url,completedsize,filesize,status) values(?,?,?,?,?)"; object[] bindargs = {filestatus.getname(), filestatus.geturl(), filestatus.getcompletedsize(), filestatus.getfilesize(), filestatus.getstatus()}; database.execsql(sql, bindargs); database.settransactionsuccessful(); } catch (sqlexception e) { e.printstacktrace(); } finally { database.endtransaction(); } } } /** * @param context * @param compeletedsize * @param threadid * @param urlstr 这里是更新数据库,建议在保存一个表格的时候就对另一个表格数据库进行更新 */ public void updatainfos(int threadid, int compeletedsize, string urlstr, context context) { synchronized (lock) { string sql = "update " + table_download_info + "set completed_size = ? where thread_id =? and url=?"; string localsql = "update " + table_localdownload_info + "set completedsize = (select sum(completed_size) from " + table_download_info + "where url=? group by url ) where url=?"; object[] bindargs = {compeletedsize, threadid, urlstr}; object[] localargs = {urlstr, urlstr}; sqlitedatabase database = dbhelper.getwritabledatabase(); database.begintransaction(); try { database.execsql(sql, bindargs); database.execsql(localsql, localargs); database.settransactionsuccessful(); } catch (sqlexception e) { e.printstacktrace(); } finally { database.endtransaction(); } } } /** * @param url 更新文件的状态,0为正在下载,1为已经下载完成,2为下载出错 **/ public void updatefilestatus(string url) { synchronized (file_lock) { string sql = "update " + table_localdownload_info + " set status = ? where url = ?"; object[] bindargs = {1, url}; sqlitedatabase database = dbhelper.getwritabledatabase(); database.begintransaction(); try { database.execsql(sql, bindargs); database.settransactionsuccessful(); } catch (sqlexception e) { e.printstacktrace(); } finally { database.endtransaction(); } } } /** * @return list<filestatus> * 取出本地下载列表数据,如在重新进入应用时,要重新把进度之类的设置好 **/ public list<filestatus> getfilestatus() { list<filestatus> list = new arraylist<filestatus>(); sqlitedatabase database = dbhelper.getreadabledatabase(); //string sql = "slect * from " + table_localdownload_info + ""; //不能用,需要哪些条件就在语句中写出哪些条件 string sql = "select name, url, status, completedsize, filesize from " + table_localdownload_info + ""; cursor cursor = database.rawquery(sql, null); while (cursor.movetonext()) { filestatus filestate = new filestatus(cursor.getstring(0), cursor.getstring(1), cursor.getint(2), cursor.getint(3), cursor.getint(4)); list.add(filestate); } cursor.close(); return list; } /** * @param url * @param completesize * @param status 更新文件的下载状态 **/ public void updatefiledownstatus(int completesize, int status, string url) { synchronized (file_lock) { string sql = "update " + table_localdownload_info + " set completedsize = ?,status = ? where url = ?"; sqlitedatabase database = dbhelper.getwritabledatabase(); database.begintransaction(); try { object[] bindargs = {completesize, status, url}; database.execsql(sql, bindargs); database.delete(table_download_info, "url = ?", new string[]{url}); database.settransactionsuccessful(); } catch (sqlexception e) { e.printstacktrace(); } finally { database.endtransaction(); } } } /** * @param url 获取文件名称 **/ public string getfilename(string url) { string result = ""; string sql = "select name from " + table_localdownload_info + " where url = ?"; sqlitedatabase database = dbhelper.getreadabledatabase(); cursor cursor = database.rawquery(sql, new string[]{url}); if (cursor.movetonext()) { result = cursor.getstring(0); } cursor.close(); return result; } /** * 删除文件之后,要删除下载的数据,一个是用户可以重新下载 * 另一个是表再次添加一条数据的时候不出现错误 * * @param url */ public void deletefile(string url) { sqlitedatabase database = dbhelper.getwritabledatabase(); database.begintransaction(); try { database.delete(table_download_info, " url = ?", new string[]{url}); database.delete(table_localdownload_info, " url = ?", new string[]{url}); database.settransactionsuccessful(); } catch (exception e) { e.printstacktrace(); } finally { database.endtransaction(); } } /** * 关闭数据库 * * @close */ public void closedb() { dbhelper.close(); } }
downloadservice 主要代码
@suppresslint("handlerleak") public class downloadservice extends service { public ibinder binder = new mybinder(); public class mybinder extends binder { public downloadservice getservice() { return downloadservice.this; } } @override public ibinder onbind(intent intent) { return binder; } public static int number = 0; // 文件保存地址 public final string savepath = "/mnt/sdcard/multifiledownload/"; // 存放下载列表的引用 public static list<filestatus> list = new arraylist<filestatus>(); public static map<string, string> localdownlist = new hashmap<string, string>(); // 保存每个文件下载的下载器 public static map<string, downloader> downloaders = new hashmap<string, downloader>(); // 每个下载文件完成的长度 private map<string, integer> completesizes = new hashmap<string, integer>(); // 每个下载文件的总长度 private map<string, integer> filesizes = new hashmap<string, integer>(); private downloader downloader; private int threadcount = 5; private dao dao; private downloadcallback loadcallback; private filestatus mfilestatus = null; private handler handler = new handler() { @override public void handlemessage(message msg) { super.handlemessage(msg); if (msg.what == 1) { string url = (string) msg.obj; int length = msg.arg1; int completesize = completesizes.get(url); int filesize = filesizes.get(url); completesize += length; completesizes.put(url, completesize); synchronized (list) { for (int i = 0; i < list.size(); i++) { filestatus filestatus = list.get(i); if (filestatus.geturl().equals(url)) { if (completesize == filestatus.getfilesize()) { system.out.println("-----------下载完成:"+filestatus.getname()+":"+completesize+"-----"+filestatus.getfilesize()); list.set(i, new filestatus(filestatus.getname(), filestatus.geturl(), 1, completesize, filestatus.getfilesize())); dao.updatefiledownstatus(completesize, 1, url); } else { list.set(i, new filestatus(filestatus.getname(), filestatus.geturl(), 0, completesize, filestatus.getfilesize())); } mfilestatus = list.get(i); } } this.postdelayed(new runnable() { @override public void run() { if (loadcallback != null && mfilestatus != null) { loadcallback.refreshui(mfilestatus); } } }, 1000); } } } }; @override public void oncreate() { super.oncreate(); dao = dao.getinstance(this); list = dao.getfilestatus(); for (filestatus filestatus : list) { localdownlist.put(filestatus.geturl(), filestatus.geturl()); } timer timer = new timer(); timer.schedule(new timertask() { @override public void run() { number++; } }, 0, 1000); } public void download(final button button, final string url, final string name, final handler mhandler) { if (dao.isexist(url)) { toast.maketext(this, "别点了,已经在下载了", toast.length_short).show(); return; } final string filename = name + url.substring(url.lastindexof(".")); new thread(new runnable() { @override public void run() { downloader = downloaders.get(url); if (downloader == null) { downloader = new downloader(url, savepath, filename, threadcount, downloadservice.this, handler); downloaders.put(url, downloader); } if (downloader.isdownloading()) return; loadinfo loadinfo = downloader.getdownloaderinfors(); if(loadinfo != null) { filestatus filestatus = new filestatus(filename, url, 0, loadinfo.getcomplete(), loadinfo.getfilesize()); dao.insertfilestatus(filestatus); completesizes.put(url, loadinfo.getcomplete()); filesizes.put(url, filestatus.getfilesize()); list.add(filestatus); localdownlist.put(url, url); downloader.download(); message msg = new message(); msg.what = 1; msg.obj = button; mhandler.sendmessage(msg); } else { message msg = new message(); msg.what = 2; msg.obj = button; mhandler.sendmessage(msg); } } }).start(); } //暂停下载 public void pause(downloader downloader) { downloader.pause(); } //继续下载 public void redownload(final button button, final string url, final string name, final handler mhandler) { new thread(new runnable() { @override public void run() { string filename = dao.getfilename(url); downloader = downloaders.get(url); if (downloader == null) { downloader = new downloader(url, savepath, filename, threadcount, downloadservice.this, handler); downloaders.put(url, downloader); } if (downloader.isdownloading()) return; loadinfo loadinfo = downloader.getdownloaderinfors(); if(loadinfo != null && !filename.equals("")) { if(!completesizes.containskey(url)) { completesizes.put(url, loadinfo.getcomplete()); } if(!filesizes.containskey(url)) { filesizes.put(url, loadinfo.getfilesize()); } downloader.download(); message msg = new message(); msg.what = 1; msg.obj = button; mhandler.sendmessage(msg); } else { message msg = new message(); msg.what = 2; msg.obj = button; mhandler.sendmessage(msg); } } }).start(); } public void delete(final string url) { downloader down = downloaders.get(url); if(down != null) { down.pause(); } handler.postdelayed(new runnable() { @override public void run() { dao.deletefile(url); for (int i = 0; i < list.size(); i++) { filestatus filestatus = list.get(i); if (filestatus.geturl().equals(url)) { list.remove(i); } } localdownlist.remove(url); downloaders.remove(url); completesizes.remove(url); filesizes.remove(url); if(loadcallback != null) { loadcallback.deletefile(url); } } }, 1000); } public interface downloadcallback { public void refreshui(filestatus filestatus); public void deletefile(string url); } public void setloadcallback(downloadcallback loadcallback) { this.loadcallback = loadcallback; } }
下载工具类downloadutil
/** * created by shancancan on 2017/3/7 0007. */ public class downloadutil { /** * 此类的主要功能 * 1、检查是否下载 * 2、下载文件,文件的下载采用httpurlconnection */ private string downpath;// 下载路径 private string savepath;// 保存路径 private string filename;// 文件名称 private int threadcount;// 线程数 private handler mhandler; private dao dao; private context context; private int filesize;// 文件大小 private int range; private list<downloadinfo> infos;// 存放下载信息类的集合 private int state = init; private static final int init = 1;// 定义三种下载的状态:初始化状态,正在下载状态,暂停状态 private static final int downloading = 2; private static final int pause = 3; /** * 构造方法,获取dao的对象 * * @param downpath * @param savepath * @param filename * @param threadcount * @param context * @param mhandler */ public downloadutil(string downpath, string savepath, string filename, int threadcount, handler mhandler, context context) { this.downpath = downpath; this.savepath = savepath; this.filename = filename; this.threadcount = threadcount; this.mhandler = mhandler; this.context = context; dao = dao.getinstance(context); } /** * 判断是否pause **/ public boolean ispause() { return state == pause; } /** * 判断是否downloading */ public boolean isdownloading() { return state == downloading; } /** * @param url 判断是否是第一次下载,利用dao查询数据库中是否有下载这个地址的记录 */ private boolean isfirst(string url) { return dao.isfirstdownload(url); } /** * 获取要下载的东西 */ public loaditeminfo getdownloadinfos() { if (isfirst(downpath)) { if (initfirst()) {//如果是第一次下载的话,要进行初始化,1.获得下载文件的长度 2.创建文件,设置文件的大小 range = this.filesize / this.threadcount; infos = new arraylist<downloadinfo>(); //这里就是启动多线程下载,看出来了吗?配合randomaccessfile。每一个downloadinfo就是randomaccessfile文件的一部分 for (int i = 0; i < this.threadcount - 1; i++) { downloadinfo info = new downloadinfo(i, i * range, (i + 1) * range - 1, 0, downpath); infos.add(info); } downloadinfo info = new downloadinfo(this.threadcount - 1, (this.threadcount - 1) * range, this.filesize, 0, downpath); infos.add(info); dao.saveinfos(infos, this.context); //(string urldownload, int completepercent, int filesize) loaditeminfo loadinfo = new loaditeminfo(this.downpath, 0, this.filesize); return loadinfo; } else { return null; } } else { //不是第一次下载,我们应该怎么做呢?从数据库里面取回来 infos = dao.getinfos(this.downpath); if (infos != null && infos.size() > 0) { int size = 0; int completesize = 0; for (downloadinfo info : infos) { completesize += info.getcompletedsize(); size += info.getendposition() - info.getstartposition() + this.threadcount - 1; } loaditeminfo loadinfo = new loaditeminfo(this.downpath, completesize, size); return loadinfo; } else { return null; } } } // 设置暂停 public void pause() { state = pause; } // 重置下载状态,将下载状态设置为init初始化状态 public void reset() { state = init; } /** * 基本上,randomaccessfile的工作方式是,把datainputstream和dataoutputstream结合起来,再加上它自己的一些方法, * 比如定位用的getfilepointer( ),在文件里移动用的seek( ),以及判断文件大小的length( )、skipbytes()跳过多少字节数。 * 此外,它的构造函数还要一个表示以只读方式("r"),还是以读写方式("rw")打开文件的参数 (和c的fopen( )一模一样)。它不支持只写文件。 */ private boolean initfirst() { boolean result = true; httpurlconnection conn = null; randomaccessfile randomfile = null; url url = null; try { url = new url(downpath); conn = (httpurlconnection) url.openconnection(); conn.setconnecttimeout(5 * 1000); conn.setrequestmethod("get"); // 如果http返回的代码是200或者206则为连接成功 if (conn.getresponsecode() == 200 || conn.getresponsecode() == 206) //状态码(206),表示服务器已经执行完部分对资源的get请求 { filesize = conn.getcontentlength();// 得到文件的大小 if (filesize <= 0) { //("网络故障,无法获取文件大小"); return false; } file dir = new file(savepath); // 如果文件目录不存在,则创建 if (!dir.exists()) { if (dir.mkdirs()) { //("mkdirs success."); } } file file = new file(this.savepath, this.filename); randomfile = new randomaccessfile(file, "rwd"); randomfile.setlength(filesize);// 设置保存文件的大小 randomfile.close(); conn.disconnect(); } } catch (exception e) { e.printstacktrace(); result = false; } finally { if (randomfile != null) { try { randomfile.close(); } catch (ioexception e) { e.printstacktrace(); } } if (conn != null) { conn.disconnect(); } } return result; } /** * 下面的这个方法就是开启多线程进行下载了数据了 */ public void download() { if (infos != null) { if (state == downloading) { return; } state = downloading;// 把状态设置为正在下载 for (downloadinfo info : infos) {//为什么说我们是多线程呢?因为我们分别用新线程去下载刚才分割好的一个randomaccessfile文件 new downloadthread(info.getthreadid(), info.getstartposition(), info.getendposition(), info.getcompletedsize(), info.geturl(), this.context).start(); } } } /** * 现在要创建线程用来下载了,这里采用内部类 */ public class downloadthread extends thread { private int threadid; private int startpostion; private int endpostion; private int compeletedsize; private string url; private context context; public static final int progress = 1; public downloadthread(int threadid, int startpostion, int endpostion, int compeletedsize, string url, context context) {//构造方法,传入特定的参数 this.threadid = threadid; this.startpostion = startpostion; this.endpostion = endpostion; this.compeletedsize = compeletedsize; this.url = url; this.context = context; } //开始下载 @override public void run() { httpurlconnection conn = null; randomaccessfile randomaccessfile = null; inputstream instream = null; file file = new file(savepath, filename); url url = null; try { url = new url(this.url); conn = (httpurlconnection) url.openconnection(); constructconnection(conn); if (conn.getresponsecode() == 200 || conn.getresponsecode() == 206) { randomaccessfile = new randomaccessfile(file, "rwd"); randomaccessfile.seek(this.startpostion + this.compeletedsize);//randomaccessfile移动指针,到需要下载的块 instream = conn.getinputstream(); byte buffer[] = new byte[4096];//这个4096为么子呢?我也不知道,就是看阿里的人下载apk的时候都用4096,我也用 int length = 0; while ((length = instream.read(buffer, 0, buffer.length)) != -1) { randomaccessfile.write(buffer, 0, length); compeletedsize += length; // 更新数据库中的下载信息 dao.updatainfos(threadid, compeletedsize, this.url, this.context); // 用消息将下载信息传给进度条,对进度条进行更新 message message = message.obtain(); message.what = progress; message.obj = this.url; message.arg1 = length; mhandler.sendmessage(message);// 给downloadservice发送消息 if (state == pause) { //("-----pause-----"); return; } } // ("------------线程:" + this.threadid + "下载完成"); } } catch (ioexception e) { e.printstacktrace(); //("-----下载异常-----"); 这里下载异常我就不处理了,你可以发一条重新下载的消息 } finally {//用完只后流要关闭,不然容易造成资源抢占,内存泄漏 try { if (instream != null) { instream.close(); } if (randomaccessfile != null) { randomaccessfile.close(); } if (conn != null) { conn.disconnect(); } } catch (ioexception e) { e.printstacktrace(); } } } /** * 构建请求连接时的参数 返回开始下载的位置 * * @param conn */ private void constructconnection(httpurlconnection conn) throws ioexception { conn.setconnecttimeout(5 * 1000);// 设置连接超时5秒 conn.setrequestmethod("get");// get方式提交,如果你是用post请求必须添加 conn.setdooutput(true); conn.setdoinput(true); conn.setrequestproperty( "accept", "image/gif, image/jpeg, image/pjpeg, image/pjpeg, application/x-shockwave-flash, application/xaml+xml, application/vnd.ms-xpsdocument, application/x-ms-xbap, application/x-ms-application, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*"); conn.setrequestproperty("accept-language", "zh-cn"); conn.setrequestproperty("referer", this.url); conn.setrequestproperty("charset", "utf-8"); int startpositionnew = this.startpostion + this.compeletedsize; // 设置获取实体数据的范围 conn.setrequestproperty("range", "bytes=" + startpositionnew + "-" + this.endpostion); conn.setrequestproperty( "user-agent", "mozilla/4.0 (compatible; msie 8.0; windows nt 5.2; trident/4.0; .net clr 1.1.4322; .net clr 2.0.50727; .net clr 3.0.04506.30; .net clr 3.0.4506.2152; .net clr 3.5.30729)"); conn.setrequestproperty("connection", "keep-alive"); conn.connect(); } } }
github地址:https://github.com/shanlovana/downloadfiles/
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。