最近做的项目中需要实现断点下载,即用户一次下载可以分多次进行,下载过程可以中断,在目前大多数的带离线缓存的软件都是需要实现这一功能。本文阐述了通过sqlite3简单实现了一个具有断点下载功能的demo。言归正传,开始正文。

设计

数据库表存储元数据

DBHelper.java

用于业务存储的Dao

Dao.java

抽象下载信息的Bean

LoadInfo.java

呈现下载信息View

MainActivity.java

存储下载信息Bean

DownloadInfo.java

封装好的下载类

Downloader.java

代码结构

具体实现

下载信息类:DownloadInfo.java

这里的代码很简单,就是一个用来保存下载信息的类,很简单,没啥好说的,具体看注释

package entity;

public class DownloadInfo {

private int threadId;//线程ID

private int startPos;//下载起始位置

private int endPos;//下载结束位置

private int completeSize;//下载完成量

private String url;//资源URL

public DownloadInfo(int tId,int sp, int ep,int cSize,String address){

threadId=tId;

startPos=sp;

endPos=ep;

completeSize = cSize;

url=address;

}

/**

* @return the threadId

*/

public int getThreadId() {

return threadId;

}

/**

* @param threadId the threadId to set

*/

public void setThreadId(int threadId) {

this.threadId = threadId;

}

/**

* @return the startPos

*/

public int getStartPos() {

return startPos;

}

/**

* @param startPos the startPos to set

*/

public void setStartPos(int startPos) {

this.startPos = startPos;

}

/**

* @return the endPos

*/

public int getEndPos() {

return endPos;

}

/**

* @param endPos the endPos to set

*/

public void setEndPos(int endPos) {

this.endPos = endPos;

}

/**

* @return the completeSize

*/

public int getCompleteSize() {

return completeSize;

}

/**

* @param completeSize the completeSize to set

*/

public void setCompleteSize(int completeSize) {

this.completeSize = completeSize;

}

/**

* @return the url

*/

public String getUrl() {

return url;

}

/**

* @param url the url to set

*/

public void setUrl(String url) {

this.url = url;

}

@Override

public String toString() {

// TODO Auto-generated method stub

return "threadId:"+threadId+",startPos:"+startPos+",endPos:"+endPos+",completeSize:"+completeSize+",url:"+url;

}

}

数据库 DBHelper.java

package db;

import android.content.Context;

import android.database.sqlite.SQLiteDatabase;

import android.database.sqlite.SQLiteOpenHelper;

public class DBHelper extends SQLiteOpenHelper {

String sql ="create table download_info (id integer PRIMARY KEY AUTOINCREMENT,"

+ "thread_id integer,"

+ "start_pos integer,"

+ "end_pos integer,"

+ "complete_size integer,"

+ "url char)";

public DBHelper(Context context) {

// TODO Auto-generated constructor stub

super(context, "download.db", null, 1);

}

@Override

public void onCreate(SQLiteDatabase db) {

// TODO Auto-generated method stub

db.execSQL(sql);

}

@Override

public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

// TODO Auto-generated method stub

}

}

数据库业务管理类 Dao.java

package db;

import java.util.ArrayList;

import java.util.List;

import android.content.Context;

import android.database.Cursor;

import android.database.sqlite.SQLiteDatabase;

import entity.DownloadInfo;

public class Dao {

private DBHelper dbHelper;

public Dao(Context context){

dbHelper = new DBHelper(context);

}

public boolean isNewTask(String url){

SQLiteDatabase db = dbHelper.getReadableDatabase();

String sql = "select count(*) from download_info where url=?";

Cursor cursor = db.rawQuery(sql, new String[]{url});

cursor.moveToFirst();

int count = cursor.getInt(0);

cursor.close();

return count == 0;

}

public void saveInfo(List infos){

SQLiteDatabase db = dbHelper.getWritableDatabase();

String sql = "insert into download_info(thread_id,start_pos,end_pos,complete_size,url) values(?,?,?,?,?)";

Object[] bindArgs= null;

for(DownloadInfo info:infos){

bindArgs=new Object[]{info.getThreadId(),info.getStartPos(),info.getEndPos(),info.getCompleteSize(),info.getUrl()};

db.execSQL(sql, bindArgs);

}

}

public List getInfo(String url){

SQLiteDatabase db = dbHelper.getReadableDatabase();

List infos = new ArrayList();

String sql ="select thread_id,start_pos,end_pos,complete_size,url from download_info where url=?";

Cursor cursor=db.rawQuery(sql, new String[]{url});

while(cursor.moveToNext()){

DownloadInfo info = new DownloadInfo(cursor.getInt(0), cursor.getInt(1), cursor.getInt(2), cursor.getInt(3),cursor.getString(4));

infos.add(info);

}

cursor.close();

return infos;

}

public void deleteInfo(String url){

SQLiteDatabase db = dbHelper.getWritableDatabase();

db.delete("download_info", "url=?", new String[]{url});

db.close();

}

public void updateInfo(int completeSize,int threadId,String url){

SQLiteDatabase db = dbHelper.getWritableDatabase();

String sql ="update download_info set complete_size=? where thread_id=? and url=?";

db.execSQL(sql, new Object[]{completeSize,threadId,url});

}

public void closeDB(){

dbHelper.close();

}

}

当前状态保存类 LoadInfo.java

package entity;

public class LoadInfo {

private int fileSize;

private int completeSize;

private String url;

public LoadInfo(int fs,int cSize,String address){

fileSize=fs;

completeSize = cSize;

url=address;

}

/**

* @return the fileSize

*/

public int getFileSize() {

return fileSize;

}

/**

* @param fileSize the fileSize to set

*/

public void setFileSize(int fileSize) {

this.fileSize = fileSize;

}

/**

* @return the completeSize

*/

public int getCompleteSize() {

return completeSize;

}

/**

* @param completeSize the completeSize to set

*/

public void setCompleteSize(int completeSize) {

this.completeSize = completeSize;

}

/**

* @return the url

*/

public String getUrl() {

return url;

}

/**

* @param url the url to set

*/

public void setUrl(String url) {

this.url = url;

}

}

下载助手类:Downloader.java

package com.winton.downloadmanager;

import java.io.File;

import java.io.IOException;

import java.io.InputStream;

import java.io.RandomAccessFile;

import java.net.HttpURLConnection;

import java.net.MalformedURLException;

import java.net.URL;

import java.util.ArrayList;

import java.util.List;

import android.content.Context;

import android.os.Handler;

import android.os.Message;

import db.Dao;

import entity.DownloadInfo;

import entity.LoadInfo;

public class Downloader {

private String url;

private String localPath;

private int threadCount;

private Handler mHanler;

private Dao dao;

private int fileSize;

private List infos;

private final static int INIT = 1;

private final static int DOWNLOADING =2;

private final static int PAUSE =3;

private int state = INIT;

public Downloader(String address,String lPath,int thCount,Context context,Handler handler){

url =address;

localPath = lPath;

threadCount = thCount;

mHanler = handler;

dao = new Dao(context);

}

public boolean isDownloading(){

return state == DOWNLOADING;

}

public LoadInfo getDownLoadInfos(){

if(isFirstDownload(url)){

init();

int range = fileSize/threadCount;

infos = new ArrayList();

for(int i=0;i<=threadCount-1;i++){

DownloadInfo info = new DownloadInfo(i, i*range, (i+1)*range-1, 0, url);

infos.add(info);

}

dao.saveInfo(infos);

return new LoadInfo(fileSize, 0, url);

}else{

infos = dao.getInfo(url);

int size = 0;

int completeSize =0;

for(DownloadInfo info:infos){

completeSize += info.getCompleteSize();

size += info.getEndPos()-info.getStartPos()+1;

}

return new LoadInfo(size, completeSize, url);

}

}

public boolean isFirstDownload(String url){

return dao.isNewTask(url);

}

public void init(){

try {

URL mUrl = new URL(this.url);

HttpURLConnection connection = (HttpURLConnection)mUrl.openConnection();

connection.setConnectTimeout(5000);

connection.setRequestMethod("GET");

fileSize = connection.getContentLength();

File file = new File(localPath);

if(!file.exists()){

file.createNewFile();

}

RandomAccessFile accessFile = new RandomAccessFile(file, "rwd");

accessFile.setLength(fileSize);

accessFile.close();

connection.disconnect();

} catch (MalformedURLException e) {

// TODO Auto-generated catch block

e.printStackTrace();

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

public void download(){

if(infos != null){

if(state ==DOWNLOADING){

return;

}

state = DOWNLOADING;

for(DownloadInfo info:infos){

new DownloadThread(info.getThreadId(), info.getStartPos(), info.getEndPos(), info.getCompleteSize(), info.getUrl()).start();

}

}

}

class DownloadThread extends Thread{

private int threadId;

private int startPos;

private int endPos;

private int completeSize;

private String url;

public DownloadThread(int tId,int sp,int ep,int cSize,String address) {

// TODO Auto-generated constructor stub

threadId=tId;

startPos=sp;

endPos = ep;

completeSize = cSize;

url = address;

}

@Override

public void run() {

// TODO Auto-generated method stub

HttpURLConnection connection = null;

RandomAccessFile randomAccessFile = null;

InputStream is = null;

try {

URL mUrl = new URL(url);

connection = (HttpURLConnection)mUrl.openConnection();

connection.setConnectTimeout(5000);

connection.setRequestMethod("GET");

connection.setRequestProperty("Range", "bytes="+(startPos+completeSize)+"-"+endPos);

randomAccessFile = new RandomAccessFile(localPath, "rwd");

randomAccessFile.seek(startPos+completeSize);

is=connection.getInputStream();

byte[] buffer = new byte[4096];

int length =-1;

while((length=is.read(buffer)) != -1){

randomAccessFile.write(buffer, 0, length);

completeSize +=length;

dao.updateInfo(threadId, completeSize, url);

Message msg = Message.obtain();

msg.what=1;

msg.obj=url;

msg.arg1=length;

mHanler.sendMessage(msg);

if(state==PAUSE){

return;

}

}

} catch (MalformedURLException e) {

// TODO Auto-generated catch block

e.printStackTrace();

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}finally{

try {

is.close();

randomAccessFile.close();

connection.disconnect();

dao.closeDB();

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

}

}

public void delete(String url){

dao.deleteInfo(url);

}

public void reset(){

state=INIT;

}

public void pause(){

state=PAUSE;

}

}

View呈现类:MainActivity.java

package com.winton.downloadmanager;

import android.app.Activity;

import android.os.Bundle;

import android.os.Environment;

import android.os.Handler;

import android.os.Message;

import android.view.View;

import android.view.View.OnClickListener;

import android.widget.Button;

import android.widget.ProgressBar;

import android.widget.TextView;

import android.widget.Toast;

import entity.LoadInfo;

public class MainActivity extends Activity implements OnClickListener{

private TextView name;

private ProgressBar process;

private Button start,stop;

private Downloader downloader;

//处理下载进度UI的

Handler handler = new Handler(){

public void handleMessage(android.os.Message msg) {

if(msg.what==1){

name.setText((String)msg.obj);

int lenght = msg.arg1;

process.incrementProgressBy(lenght);

}

if(msg.what==2){

int max =msg.arg1;

process.setMax(max);

Toast.makeText(getApplicationContext(), max+"", 1).show();

}

};

};

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

name=(TextView)findViewById(R.id.tv_name);

process=(ProgressBar)findViewById(R.id.pb_download);

start = (Button)findViewById(R.id.bt_start);

stop = (Button)findViewById(R.id.bt_stop);

start.setOnClickListener(this);

stop.setOnClickListener(this);

downloader=new Downloader("http://img4.duitang.com/uploads/item/201206/11/20120611174542_5KRMj.jpeg", Environment.getExternalStorageDirectory().getPath()+"/test1.jpg", 1, getApplicationContext(), handler);

}

@Override

public void onClick(View v) {

// TODO Auto-generated method stub

if(v==start){

new Thread(new Runnable() {

@Override

public void run() {

// TODO Auto-generated method stub

LoadInfo loadInfo = downloader.getDownLoadInfos();

Message msg =handler.obtainMessage();

msg.what=2;

msg.arg1=loadInfo.getFileSize();

handler.sendMessage(msg);

downloader.download();

}

}).start();

return;

}

if(v==stop){

downloader.pause();

return;

}

}

}

运行效果

总体比较简单,基本实现了 断点下载的功能,而且开启了多个线程去实现分块下载,对初学的同学有一定的帮助。

这些代码我也是从网上各种搜集而来,自己亲自动手敲了一遍,并做了一些小的改动,对整个断点下载的过程有了一个深刻的认识。因此平时要多敲代码,善于总结,必能有所收获。

android 断点下载的实现,Android实现断点下载的方法相关推荐

  1. [转]2014年最新810多套android源码2.46GB免费一次性打包下载

    转载自:http://www.eoeandroid.com/thread-497046-1-1.html 感谢该博客主人无私奉献~~ 下面的源码是从今年3月份开始不断整理源码区和其他网站上的安卓例子源 ...

  2. 转--2014年最新810多套android源码2.46GB免费一次性打包下载

    转载自:http://www.eoeandroid.com/thread-497046-1-1.html 感谢该博客主人无私奉献~~ 下面的源码是从今年3月份开始不断整理源码区和其他网站上的安卓例子源 ...

  3. 2014年最新720多套Android源码2.0GB免费一次性打包下载

    之前发过一个帖子,但是那个帖子有点问题我就重新发一个吧,下面的源码是我从今年3月份开始不断整理源码区和其他网站上的android源码,目前总共有720套左右,根据实现的功能被我分成了100多个类,总共 ...

  4. android 5秒后进入,Android/Java:如何在5秒后停止下载?

    我正在使用AsyncTask来下载文件,目的是测量连接的下载速度.我想在5秒后停止下载,以便我可以检查下载的总字节数并计算速度.下面是我使用(这被放置在doInBackground()方法中)的代码: ...

  5. Android多线程分析之一:使用Thread异步下载图像

    打算整理一下对 Android Framework 中多线程相关知识的理解,主要集中在 Framework 层的 Thread, Handler, Looper, MessageQueue, Mess ...

  6. Android Service下载文件并自定义通知提示下载

    最近要做一个更新sdk,里面用到了service后台下载,自定义通知提示下载进度,下面直接贴上代码. 下面是UpdateUtils.java ,告诉你如何使用 package com.cnziz.up ...

  7. Android中通过SeekBar手动控制ProgressBar与模拟下载自动更新进度条

    场景 进度条的常用场景: 通过SeekBar拖动进而更新ProgressBar进度条,比如调整音量效果等. 模拟下载实现自动更新进度条. 注: 博客: https://blog.csdn.net/ba ...

  8. 云炬Android开发报错处理教程 完美解决Android Studio maven { url ‘https://jitpack.io‘ } 无法下载问题

    有个项目好久没有运行了,这次刚好有个bug要协助调试,由于AndroidStudio已经升级到最新稳定版3.5了,运行项目居然报错(一脸懵逼) Could not GET 'https://jitpa ...

  9. android源码下载与编译,Android源码下载并编译

    Android源代码下载与编译 - 2020 1.下载repo工具 到清华mirror下载repo curl https://mirrors.tuna.tsinghua.edu.cn/git/git- ...

最新文章

  1. r语言 林元震_科学网—ASReml-R之简介 - 林元震的博文
  2. SimpleDateFormat处理 dd-MMM-yy类型日期
  3. c 语言实现汇文, 瞎写
  4. Android中minSdkVersion、targetSdkVersion、maxSdkVersion的作用
  5. 设计模式的一些小整理
  6. 基于JAVA+SpringMVC+Mybatis+MYSQL的高校社团管理系统
  7. oracle怎么设置脚本,ORACLE安装预设置脚本
  8. CAD手机看图:CAD图纸中添加的批注发送给别人后批注却消失了?
  9. 【PAT B1024】科学计数法(C语言)
  10. 复利思维,静待时间的玫瑰慢慢绽放
  11. pandas进阶 期中练习
  12. Unity中获取AnimationClip的关键帧信息
  13. java 银联支付_Java 银联支付官网demo测试及项目整合代码
  14. 华为系统和计算机,电脑手机合二为一 华为多屏协同让电脑与手机亲密互动
  15. win10操作系统点击鼠标右键反应很慢怎么办
  16. 如何使用openssl创建根CA和中间CA以及签署其他client证书请求
  17. 计算机解决问题的几个必要,1–1计算机解决问题的过程.ppt
  18. java.lang.IllegalArgumentException: Scrapped or attached views may not be recycled.
  19. Error creating bean with name ‘processEngine‘: FactoryBean threw exception on object creation; neste
  20. 交互设计指南 iphone_交互设计:角色创建指南

热门文章

  1. echart vue
  2. c++_设计一个 Studnet(学生)类
  3. 小说程序源码 自动采集
  4. 测试路由器的防火墙配置,wan:入站数据,出站数据,转发
  5. Python男票管理系统
  6. freemarker 解析对象的某元素_FreeMarker标签介绍及各种数据类型处理
  7. 基于机器学习与深度学习的金融风控贷款违约预测
  8. 项目管理(PMP)项目进度管理
  9. Unity3d制作简单拼图游戏
  10. bzoj4167 永远亭的竹笋采摘