自己动手实现一个Android断点下载
来源:互联网 发布:java自带的观察者模式 编辑:程序博客网 时间:2024/05/21 10:35
一、断点下载原理及步骤
对于断点下载,就是下载的过程中,都会出现一些异常情况,导致下载中断。虽说可以重新下载,但是这对于数据比较大的来说,这是很麻烦很蛋疼的事。
原理:
在下载中断的时候,通过数据库,记录中断的文件信息。待恢复上传的时候,从数据库中读取中断的文件信息。通过RandomAccessFile这个类可以让文件继续从中断的位置上传。
步骤:
1. 获取下载链接,首先根据下载链接到数据库查找一下是否有重复的下载任务,有的话获取数据继续下载,没有的话,新建任务,获取文件对象,传给下载服务。
2. 新建一个下载服务,方便应用退出时,能继续在后台下载。
3. 创建一个数据库,用来存储程序出现异常中断时,能够及时保存下载信息,方便下次读取继续下载。
4. 创建一个线程,用来获取待下载文件的长度和执行下载线程。
5. 在不断写文件的过程中,通过广播刷新下载进度。
二、代码实现
package com.example.river.download;import java.io.Serializable;/** * Created by Administrator on 2017/10/18. */public class FileInfo implements Serializable{ private String fileName; private String url; //文件的大小 private int len; //文件结束位置 private int finished; private boolean isDownloading; public FileInfo(){ }public FileInfo(String fileName,String url){ this.fileName = fileName; this.url = url;} public boolean isDownloading() { return isDownloading; } public void setDownloading(boolean downloading) { isDownloading = downloading; } public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } public int getLen() { return len; } public void setLen(int len) { this.len = len; } public int getFinished() { return finished; } public void setFinished(int finished) { this.finished = finished; } public String getFileName() { return fileName; } public void setFileName(String fileName) { this.fileName = fileName; }}
start.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Intent intent = new Intent(MainActivity.this, DownloadService.class); if (fileInfo.isDownloading()) { fileInfo.setDownloading(false); start.setText("继续"); } else { fileInfo.setDownloading(true); start.setText("暂停"); } intent.setAction("start"); intent.putExtra("fileInfo", fileInfo); startService(intent); } }); restart.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { start.setText("暂停"); fileInfo.setDownloading(true); Intent intent = new Intent(MainActivity.this, DownloadService.class); fileInfo.setFinished(0); intent.setAction("restart"); intent.putExtra("fileInfo", fileInfo); startService(intent); } }); receiver = new ProgressBroadcast(); IntentFilter filter = new IntentFilter(); filter.addAction("android.intent.action.ProgressBroadcast");//注册receiver registerReceiver(receiver, filter);
广播更新进度 public class ProgressBroadcast extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { int progress = intent.getIntExtra("finished", 0); mProgressBar.setProgress(progress); } }
检查数据库private FileInfo checkDB(){ DBHelper dbHelper = new DBHelper(MainActivity.this); SQLiteDatabase db = dbHelper.getReadableDatabase(); fileInfo= dbHelper.queryData(db,"http://www.21yey.com/clientdownload/android/family.apk"); if (fileInfo.getFinished() > 0) { mProgressBar.setProgress(fileInfo.getFinished() * 100 / fileInfo.getLen()); start.setText("继续"); }else { fileInfo = new FileInfo("family.apk", "http://www.21yey.com/clientdownload/android/family.apk"); } return fileInfo; }
后台下载服务,以便应用退出可以继续下载 public class DownloadService extends IntentService{ public static final String ACTION_START = "start"; public static final String ACTION_RESTART = "restart"; public static final String ACTION_UPDATE = "update"; public DownloadService() { super("download"); } @Override protected void onHandleIntent(Intent intent) { TaskManager task = TaskManager.getInstance(); FileInfo fileInfo = (FileInfo) intent.getSerializableExtra("fileInfo"); if(intent.getAction().equals(ACTION_START)){ if(fileInfo.isDownloading()){ task.start(DownloadService.this,fileInfo); }else { task.stop(); } } if(intent.getAction().equals(ACTION_RESTART)){ task.restart(DownloadService.this,fileInfo); } }}
任务调度public class TaskManager { private Map<String,FileInfo> map = new HashMap<>(); private boolean isPause; public static class TaskHolder{ private static final TaskManager instance = new TaskManager(); } public static TaskManager getInstance(){ return TaskHolder.instance; } //恢复任务 public void start(Context context,FileInfo fileInfo){ if(map.get(fileInfo.getUrl())==null){ map.put(fileInfo.getUrl(),fileInfo); } DownloadTask task = new DownloadTask(map.get(fileInfo.getUrl()),context); isPause = false; task.start(); } public void stop(){ isPause =true; } public void restart(Context context,FileInfo fileInfo){ try { map.clear(); File file = new File(DownloadTask.FILE_PATH,fileInfo.getFileName()); if (file.exists()){ file.delete(); } Thread.sleep(100); }catch (Exception e){ return; } start(context,fileInfo); } public boolean isPause() { return isPause; } public void setPause(boolean pause) { isPause = pause; }}
获取待下载的文件长度 int length = -1; try { HttpURLConnection conn = null; URL url = new URL(info.getUrl()); conn = (HttpURLConnection) url.openConnection(); conn.setRequestMethod("GET"); conn.setConnectTimeout(5000); if(conn.getResponseCode() ==200){ length =conn.getContentLength(); } if(length<0){ return; } File dir = new File(DownloadTask.FILE_PATH); if(!dir.exists()){ dir.mkdir(); } info.setLen(length); conn.disconnect(); } catch (IOException e) { e.printStackTrace(); }
执行下载任务 HttpURLConnection connection = null; RandomAccessFile raf = null; try { URL urls = new URL(info.getUrl()); connection = (HttpURLConnection) urls.openConnection(); connection.setRequestMethod("GET"); connection.setConnectTimeout(3000); //获取上次下载位置 int start = info.getFinished(); connection.setRequestProperty("Range","bytes="+start+"-"+length); //设置文件写入位置 File file = new File(FILE_PATH,info.getFileName()); raf= new RandomAccessFile(file,"rwd"); raf.seek(start); finished += info.getFinished(); if(connection.getResponseCode() == 206){ InputStream is =connection.getInputStream(); byte[] bytes = new byte[1024*4]; int len; while ((len = is.read(bytes))!=-1){ raf.write(bytes,0,len); finished+=len; info.setFinished(finished); if(TaskManager.getInstance().isPause()){ info.setDownloading(false); dbHelper.insert(db,info); db.close(); return; } //实时更新下载进度 Intent intent = new Intent(DownloadService.ACTION_UPDATE); intent.putExtra("finished", finished * 100 / length); intent.setAction("android.intent.action.ProgressBroadcast"); context.sendBroadcast(intent); } info.setDownloading(false); dbHelper.insert(db,info); db.close(); } } catch (Exception e) { e.printStackTrace(); }
运行效果:
三、总结
我简单的实现单任务单线程的下载(适合文件较小)。后续会实现单任务多线程下载、多任务多线程下载(文件较大的)和上传,敬请关注。虽然代码简陋,但简洁思路清晰比较好理解。我的目的不是实现一个高性能可扩展的下载器,而是展示具体如何实现下载的一个流程。当然,我实现的代码都是比较基础的,比较好理解。
阅读全文
0 0
- 自己动手实现一个Android断点下载
- Android断点下载实现
- android 多线程断点下载实现
- android如何实现断点下载
- Android实现多线程断点下载
- Android实现多线程断点下载
- 自己动手实现一个Android Studio插件
- 自己动手实现一个Android Studio插件
- android实现多任务断点下载
- Android多线程实现文件断点下载
- Android多线程断点下载的实现示例
- Android实现网络多线程断点下载介绍
- Android 多线程断点下载的实现方法
- Android多线程断点下载简单实现
- Android中实现多线程断点下载
- android实现多任务断点下载
- Android下实现多线程断点下载
- Android原生实现多线程断点下载
- hello.ko---Makefile
- Line论文中的Alias Sampling Algorithm 分析
- 回首Java——堆排序
- 会场安排问题
- UE4实现纹理缩放(将纹理坐标进行缩放)
- 自己动手实现一个Android断点下载
- 数据库一表分两表导入数据的SQL 语句
- appDelegate
- Centos7安装-单节点Torque
- 管道物流装卸系统
- OpenNI+OpenCV对Kinect采集的彩色图和深度图进行滤波
- 喷水装置(二)
- 发布自己的android library到maven和jcenter
- NOIP复赛复习(十四)字符串算法巩固与提高