android断点续传下载文件
来源:互联网 发布:中兴刷机软件 编辑:程序博客网 时间:2024/06/09 18:46
这里有两个功能点。
1、下载
2、下载暂停后可以在暂停位置下载。
所以暂定涉及到的技术是,http网络请求,多线程,sqlite数据库缓存下载位置。
代码流的处理流程:从主activity按钮激发下载行为。委托DownloadTask子线程管理下载事务。DownloadTask调用下载器FileDownlodered完成下载文件。FileDownlodered调用多个DownloadThread线程的方式(多线程)从服务器下载文件块。DownloadThread在下载的时候实时把当前线程下载的情况记录到sqlite数据库中,记录下载位置。当在暂停后在启动时候直接从暂停位置开始下载。
activity ->DownloadTask ->FileDownlodered ->DownloadThread ->db;
主activity的按钮事件响应代码
@Override public void onClick(View v) { // TODO Auto-generated method stub switch (v.getId()) { case R.id.startDownload: String path = pathText.getText().toString();// 获取下载路径 if (Environment.getExternalStorageState().equals( Environment.MEDIA_MOUNTED)) { // 当sd卡存在时候 // getExternalStorgeDirectory(); File saveFile = Environment .getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS); //获取到sd卡的文本目录。也是我们下载文件的目录绝对地址。 getExternalFilesDir(Environment.DIRECTORY_DOCUMENTS);download(path, saveFile);// 依据资源path,和文件在本地存放的目录地址作为参数进行下载文件 try { Log.i(TAG, path); Log.i(TAG, saveFile.getCanonicalPath().toString()); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } Log.i(TAG, "sd卡存在,开始下载"); } else { Log.e(TAG, getResources().getString(R.string.sdcarderror)); } downloadButton.setEnabled(false); stopButton.setEnabled(true); break; case R.id.stopDownload: exit(); downloadButton.setEnabled(true); stopButton.setEnabled(false); break; default: break; } }//这是下载方法的逻辑,委托了DownloadTask子线程进行下载管理。ui线程不可以用于延时的操作。public void download(String path, File saveDir) { // TODO Auto-generated method stub task = new DownloadTask(path, saveDir); new Thread(task).start(); }
下面是DownloadTask子线程对下载任务的管理逻辑。也是委托给FileDownlodered类进行实际的下载操作。这个类的主要功能是新建一个下载任务,并实现FileDownlodered下载类回调过来的反馈信息处理。
private class DownloadTask implements Runnable { private final String path; private final File saveDir; private FileDownlodered fileDownloader; public DownloadTask(String path, File saveDir) { this.path = path; this.saveDir = saveDir; } public void exit() { if (fileDownloader != null) { fileDownloader.exit(); } } // 下载任务含一个下载监听器。 DownloadProcessListener downloadProcessListener = new DownloadProcessListener() {//这个监听器是监听来自下载器FileDownlodered反馈过来的下载进度信息,然后通过handler进制更新ui @Override public void onDownloadSize(int downloadSize) { // TODO Auto-generated method stub Message msg = new Message(); msg.what = PROCESSING; msg.getData().putInt("size", downloadSize); uiHandler.sendMessage(msg); } }; @Override public void run() { // TODO Auto-generated method stub try { // new一个下载器,下载器必 //须放在这里,放在构造器里面因为设计到网络请求方面延时操作可能会报ui线程延时的异常。 fileDownloader = new FileDownlodered(getApplicationContext(), path, saveDir, 8); progressBar.setMax(fileDownloader.getFileSize()); Log.i(TAG, Thread.currentThread().getName() + "进入下载"); // 下载器开始下载 Log.i(TAG, String.valueOf(fileDownloader .download(downloadProcessListener)));//这个download方法是下载器真正执行下载功能的方法,// } catch (Exception e) { // TODO: handle exception e.printStackTrace(); uiHandler.sendMessage(uiHandler.obtainMessage(FAILURE)); } } }
FileDownlodered的download方法
这个方法主要的功能是
public int download(DownloadProcessListener listener) { try { RandomAccessFile randOut = new RandomAccessFile(this.saveFile, "rwd"); if (this.fileSize > 0) randOut.setLength(this.fileSize); randOut.close(); URL url = new URL(this.downloadUrl); // 如果data map中存放的数据记录数没能跟线程数一样。那么说明不同同一次下载操作,data记录的 // 数据要清零。 if (this.data.size() != this.threads.length) { this.data.clear(); for (int i = 0; i < this.threads.length; i++) this.data.put(i + 1, 0); this.downloadSize = 0; } Log.i(TAG, "data长度 " + String.valueOf(this.data.size())); for (int i = 0; i < this.threads.length; i++) { int downloadedLength = this.data.get(i + 1); if (downloadedLength < this.block && this.downloadSize < this.fileSize) { // 表名这个线程的任务还没开始 this.threads[i] = new DownloadThread(this, url, this.saveFile, this.block, this.data.get(i + 1), i + 1); this.threads[i].setPriority(7); this.threads[i].start(); } else { this.threads[i] = null;// 表明线程已完成下载任务 } } fileService.delete(this.downloadUrl); fileService.save(this.downloadUrl, this.data); boolean notfinished = true; while (notfinished) { Thread.sleep(90); notfinished = false; for (int i = 0; i < this.threads.length; i++) { if (this.threads[i] != null// 当每个线程都没下载完成的时候进入, && !this.threads[i].isFinished()) { notfinished = true; if (this.threads[i].getDownloadedLength() == -1) { // 判定每个线程是否发生了故障,如果发生了故障重启下载 this.threads[i] = new DownloadThread(this, url, this.saveFile, this.block, this.data.get(i + 1), i + 1); this.threads[i].setPriority(7); this.threads[i].start(); } } } if (listener != null) listener.onDownloadSize(this.downloadSize); } if (downloadSize == this.fileSize)// 如果下载的文件大小和从http头部获取的资源大小一样说明下载完成了。 //那么将所有线程记录的信息删除。 this.fileService.delete(this.downloadUrl); } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } return this.downloadSize; }
DownloadThread的run方法是直接httpconnection到远程服务器那边,然后用RandomAccessFile类可随机访问改写文件的类进行多线程下载。
@Override public void run() { // TODO Auto-generated method stub // 每个线程下载各自的每一块信息。 if (downloadedLength < block) { try {//新建一个httpurl链接 HttpURLConnection connection = (HttpURLConnection) downUrl .openConnection(); connection.setConnectTimeout(5 * 1000); connection.setRequestMethod("GET"); connection .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,*/*"); connection.setRequestProperty("Accept-Language", "zh-CN"); connection.setRequestProperty("Charset", "UTF-8"); int startPos = block * (threadId - 1) + downloadedLength;// 在每个线程里面自己计算下载的起始位置和终止位置。 int endPos = block * threadId - 1; //利用了http协议的range字段可以设置下载的位置。 connection.setRequestProperty("Range", "bytes=" + startPos + "-" + endPos); connection.setRequestProperty("Connection", "Keep-Alive"); InputStream inStream = connection.getInputStream(); byte[] buffer = new byte[1024]; int length = 0; Print("Thread: " + this.threadId + " start to download from position:\t" + startPos); RandomAccessFile threadFile = new RandomAccessFile( this.saveFile, "rwd"); threadFile.seek(startPos); while (!this.downloader.getExited() && (length = inStream.read(buffer, 0, 1024)) != -1) { //判定条件:依据downloader.getExited()是否给予了暂停信号,并当前下载块是否到了流的末尾。 threadFile.write(buffer, 0, length); downloadedLength += length; downloader.update(this.threadId, this.downloadedLength);//更新下载数据到sqlite数据库中,用于暂停后恢复下载位置用。 downloader.append(length); } threadFile.close(); inStream.close(); if (downloader.getExited()) Print("Thread: " + this.threadId + " has been paused."); else // 如果下载器没有暂停, Print("Thread: " + this.threadId + " download finish"); this.finished = true;// 无任是真的下载完成还是用于中断下载,都给出下载完的信息。 } catch (Exception e) {// 链接远程资源发生故障, // TODO: handle exception this.downloadedLength = -1; Print("Thread: " + this.threadId + ":" + e.toString()); } } }
0 0
- android断点续传下载文件
- Android实现文件下载断点续传
- Android文件下载之断点续传
- Android 文件多线程断点续传下载
- Android多线程断点续传下载文件类设计
- Android开发文件下载中的断点续传源码
- Android文件下载(实现断点续传)
- Android多线程断点续传下载文件类设计
- Android网络编程 --断点续传下载文件
- Android 文件下载,断点续传,进度更新
- Android实现断点续传下载文件,网络编程
- Android网络编程 --断点续传下载文件
- Android网络编程 --断点续传下载文件
- Android文件下载(实现断点续传)
- Android文件下载(实现断点续传)
- android 多文件多线程断点续传下载
- android 文件断点续传下载,外加下载进度提示
- Android下载文件相关--多线程下载和断点续传
- hdu 3996 Gold Mine【最大权闭包-----最小割最大流Dinic】
- error:LNK2005 已经在*.obj中定义
- Impala实践之十四:一次Impala节点故障记录(不能启动)
- tomcat源码解析(七):server和service
- JPA学习1-5
- android断点续传下载文件
- POJ 2955 Brackets (区间DP)
- 使用phonegap检测网络状态
- 简单爬虫的实现与学习笔记(完)(8/31)
- leetcode 225. Implement Stack using Queues
- Tomcat的 虚拟目录&虚拟主机 配置放方法
- BL1和BL2
- MySQL5.6 GTID模式 同步复制跳过报错解决方法
- gradle入门--11.疏忽lint毛病这特别重要 不加发布会出各种问题