Android从网络上下载文件

来源:互联网 发布:西医综合网络课程 编辑:程序博客网 时间:2024/05/21 06:22

现在网络上关于Android下载的代码很多,但是光看还是无法完全理解和掌握,所以决定自己手写一个,以加深学习。

在写下载代码之前,有几点知识必须要掌握:

1.Http请求报文格式及响应报文,可以通过使用wireshark来对报文进行抓取,查看http协议的报文

2.HttpUrlConnection的使用

3.RandomAccessFile类的使用(可断点下载)

这里写的下载是关于断点下载的。

断点下载的原理就是在请求报文中加入Range:bytes=x-y 其中x表示开始下载的位置,y表示下载到的位置,y可省略,表示到文件结尾。例如:0-  表示从文件的开头一直读到结尾。

多线程下载页是基于这个原理。例如有三个线程。文件大小为600;则:

线程1:Range:bytes=0-199;

线程2:Range:bytes=200-399;

线程3:Range:bytes=400-

建立起连接之后,获取输入流:

in=con.getInputStream();
然后利用RandomAccessFile类就行写出。这个类可以随机写入文件,通过seek方法定位到要写的位置,然后通过write方法进行写出。代码如下

public class DownLoadUtil {private static DownLoadUtil downLoadUtil;private int readTimeOut = 6 * 1000;// 读取超时时间private int connectTimeOut = 6 * 1000;// 连接超时时间private OnDownLoadListener listener;// 下载监听器private Handler handler;// 监听结果交由主线程处理private boolean isDownloading;// 下载状态private int downloadLength = 0;// 记录下载长度(应用中应保存在数据库中)private String requestUrl;private String path;// private Handler handerl;private DownLoadUtil() {// 获取主线程handler,可以让回调函数在主线程运行(volley框架就是通过这种方式让处理结果在主线程运行的)handler = new Handler(Looper.getMainLooper());}public static DownLoadUtil getInstance() {if (downLoadUtil == null) {downLoadUtil = new DownLoadUtil();}return downLoadUtil;}public void downLoad(String requestUrl, String path, int downloadLength) {this.isDownloading = true;this.requestUrl = requestUrl;this.path = path;new DownLoadThread(requestUrl, path, downloadLength).start();}// 下载线程public class DownLoadThread extends Thread {private String downloadUrl;// 下载地址private String path;// 存储路径private int downloadLength;// 已下载长度private int progressNotifyCount;// 每下载100字节更新一次public DownLoadThread(String downloadUrl, String path, int downloadLength) {this.downloadLength = downloadLength;this.path = path;this.downloadUrl = downloadUrl;}@Overridepublic void run() {// TODO Auto-generated method stub// super.run();InputStream is = null;RandomAccessFile downFile = null;HttpURLConnection con = null;try {URL url = new URL(downloadUrl);con = (HttpURLConnection) url.openConnection();con.setReadTimeout(readTimeOut);// 设置主机读取超时时间con.setConnectTimeout(connectTimeOut);// 设置连接超时时间// 断点下载所需 Range:bytes=x-y;con.setRequestProperty("Range", "bytes=" + String.valueOf(downloadLength) + "-");is = con.getInputStream();int fileLength = con.getContentLength();// 获取文件长度Log.v("fileLength", String.valueOf(fileLength));exeDownLoadInit(downloadLength, fileLength);// 下载初始化回调,返回已下载大小和文件总大小File file = new File(path);if (!file.exists()) {file.mkdir();}String[] str = downloadUrl.split("/");String fileName = str[str.length - 1];File file1 = new File(path + fileName);if (!file1.exists()) {file1.createNewFile();} else {}downFile = new RandomAccessFile(file1, "rw");downFile.seek(downloadLength);// 定位文件已经写入的位置,断点下载使用byte[] data = new byte[1024];int len;while ((len = is.read(data)) != -1) {// 文件写出,使用write(data,0,len)这个方法,当读取的长度小于1024,则只写入读取的长度// 如果使用write(data)方法,则当长度不够1024,就会在后面自动补0downFile.write(data, 0, len);downloadLength += len;downLoadUtil.downloadLength += len;progressNotifyCount++;// if(progressNotifyCount%100==0){// 这个运算就相当于progressNotifyCount%100==0// 计算机进行二进制运算速度更快,可做android优化使用// 每下载100字节,就回调一次进度,供更新进度条使用if ((progressNotifyCount & (100 - 1)) == 0) {exeDownLoadProgress(downloadLength);}// 暂停函数if (!isDownloading) {return;}}//下载完成回调if (downloadLength == fileLength) {exeDownloadComplete(fileLength);}} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();} finally {try {downFile.close();is.close();con.disconnect();} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}}}}// 交由主线程处理监听结果private void exeDownLoadProgress(final int downloadLength) {handler.post(new Runnable() {@Overridepublic void run() {// TODO Auto-generated method stublistener.downloadProgress(downloadLength);}});}private void exeDownLoadInit(final int downloadLength, final int fileLength) {handler.post(new Runnable() {@Overridepublic void run() {// TODO Auto-generated method stublistener.downloadInit(downloadLength, fileLength);}});}private void exeDownloadComplete(final int fileLength) {handler.post(new Runnable() {@Overridepublic void run() {// TODO Auto-generated method stublistener.complete(fileLength);}});}/** * 下载监听器 *  * @author Administrator * */public static interface OnDownLoadListener {/** * 请求完成回调 *  * @param fileLength */void complete(int fileLength);/** * 进度更新 *  * @param downloadLength */void downloadProgress(int downloadLength);/** * 下载初始化 *  * @param fileLength */void downloadInit(int downloadLength, int fileLength);}public void setListener(OnDownLoadListener listener) {this.listener = listener;}public void stop() {this.isDownloading = false;// downloadThread.getId();}public void restart() {isDownloading = true;downLoad(requestUrl, path, downloadLength);}}

Demo资源下载


0 0
原创粉丝点击