开头还是不说废话了直接进入主题吧!

一:关于断点下载所涉及到的知识点

1.对SQLite的增删改查(主要用来保存当前任务的一些信息)
2.HttpURLConnection的请求配置

HttpURLConnection connection = null;
//设置下载请求属性
connection.setRequestProperty();

3.RandomAccessFile 对文件进行写入

RandomAccessFile rwd = null;
//从文件的某一位置写入
rwd.seek();

4.基本的I/O流操作,以及逻辑处理

二:第一步我们先来创建一张表用来保存我们的下载信息

public class DbHelper extends SQLiteOpenHelper {public static String TABLE = "file";//表名public DbHelper(Context context) {super(context, "download.db", null, 1);}@Overridepublic void onCreate(SQLiteDatabase db) {//文件名,下载地址,下载文件的总长度,当前下载完成长度db.execSQL("create table file(fileName varchar,url varchar,length integer,finished integer)");}
}

三:第二步同时既然是对数据库的操作,那我们在DbHelper.class中来写好几个公用方法

    /*** 插入一条下载信息*/public void insertData(SQLiteDatabase db, FileInfo info) {ContentValues values = new ContentValues();values.put("fileName", info.getFileName());values.put("url", info.getUrl());values.put("length", info.getLength());values.put("finished", info.getFinished());db.insert(TABLE, null, values);}/*** 是否已经插入这条数据*/public boolean isExist(SQLiteDatabase db, FileInfo info) {Cursor cursor = db.query(TABLE, null, "url = ?", new String[]{info.getUrl()}, null, null, null, null);boolean exist = cursor.moveToNext();cursor.close();return exist;}/*** 查询已经存在的一条信息*/public FileInfo queryData(SQLiteDatabase db, String url) {Cursor cursor = db.query(TABLE, null, "url = ?", new String[]{url}, null, null, null, null);FileInfo info = new FileInfo();if (cursor != null) {while (cursor.moveToNext()) {String fileName = cursor.getString(cursor.getColumnIndex("fileName"));int length = cursor.getInt(cursor.getColumnIndex("length"));int finished = cursor.getInt(cursor.getColumnIndex("finished"));info.setStop(false);info.setFileName(fileName);info.setUrl(url);info.setLength(length);info.setFinished(finished);}cursor.close();}return info;}/*** 恢复一条下载信息*/public void resetData(SQLiteDatabase db, String url) {ContentValues values = new ContentValues();values.put("finished", 0);values.put("length", 0);db.update(TABLE, values, "url = ?", new String[]{url});}

3.从上面方法中可以看出来还有一个FileInfo对象,没错这是自己创建的一个下载任务实体类一起来看看吧

//保存下载任务信息
public class FileInfo {private String fileName;//文件名private String url;//下载地址private int length;//文件大小private int finished;//下载以已完成进度private boolean isStop = false;//是否暂停下载private boolean isDownLoading = false;//是否正在下载//......//剩下的都是对应的get and set 方法就不贴出来了,自动生成就好了

四:第三步我们创建一个类DownLoaderManger来管理我们的下载任务包括、添加下载任务、开始下载、暂停下载、重新下载

public class DownLoaderManger {public static String FILE_PATH = Environment.getExternalStorageDirectory() + "/azhong";//文件下载保存路径private DbHelper helper;//数据库帮助类private SQLiteDatabase db;private OnProgressListener listener;//进度回调监听private Map<String, FileInfo> map = new HashMap<>();//保存正在下载的任务信息private static DownLoaderManger manger;private DownLoaderManger(DbHelper helper, OnProgressListener listener) {this.helper = helper;this.listener = listener;db = helper.getReadableDatabase();}/*** 单例模式** @param helper   数据库帮助类* @param listener 下载进度回调接口* @return*/public static synchronized DownLoaderManger getInstance(DbHelper helper, OnProgressListener listener) {if (manger == null) {synchronized (DownLoaderManger.class) {if (manger == null) {manger = new DownLoaderManger(helper, listener);}}}return manger;}/*** 开始下载任务*/public void start(String url) {db = helper.getReadableDatabase();FileInfo info = helper.queryData(db, url);map.put(url, info);//开始任务下载new DownLoadTask(map.get(url), helper, listener).start();}/*** 停止下载任务*/public void stop(String url) {map.get(url).setStop(true);}/*** 重新下载任务*/public void restart(String url) {stop(url);try {File file = new File(FILE_PATH, map.get(url).getFileName());if (file.exists()) {file.delete();}Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}db = helper.getWritableDatabase();helper.resetData(db, url);start(url);}/*** 获取当前任务状态*/public boolean getCurrentState(String url) {return map.get(url).isDownLoading();}/*** 添加下载任务** @param info 下载文件信息*/public void addTask(FileInfo info) {//判断数据库是否已经存在这条下载信息if (!helper.isExist(db, info)) {db = helper.getWritableDatabase();helper.insertData(db, info);map.put(info.getUrl(), info);} else {//从数据库获取最新的下载信息db = helper.getReadableDatabase();FileInfo o = helper.queryData(db, info.getUrl());if (!map.containsKey(info.getUrl())) {map.put(info.getUrl(), o);}}}
}

五:上面代码中OnProgressListener接口,当然还有一个最最重要的DownLoadTask了这里面就是实现了如何断点下载的,下面来一起看下里面的实现逻辑吧。。。

//下载进度接口
public interface OnProgressListener {void updateProgress(int max, int progress);
}

六:重点–下载线程

/*** 下载文件线程* 从服务器获取需要下载的文件大小*/
public class DownLoadTask extends Thread {private FileInfo info;private SQLiteDatabase db;private DbHelper helper;//数据库帮助类private int finished = 0;//当前已下载完成的进度private OnProgressListener listener;//进度回调监听public DownLoadTask(FileInfo info, DbHelper helper, OnProgressListener listener) {this.info = info;this.helper = helper;this.db = helper.getReadableDatabase();this.listener = listener;info.setDownLoading(true);}@Overridepublic void run() {getLength();HttpURLConnection connection = null;RandomAccessFile rwd = null;try {URL url = new URL(info.getUrl());connection = (HttpURLConnection) url.openConnection();connection.setRequestMethod("GET");connection.setConnectTimeout(3000);//从上次下载完成的地方下载int start = info.getFinished();//设置下载位置(从服务器上取要下载文件的某一段)connection.setRequestProperty("Range", "bytes=" + start + "-" + info.getLength());//设置下载范围//设置文件写入位置File file = new File(DownLoaderManger.FILE_PATH, info.getFileName());rwd = new RandomAccessFile(file, "rwd");//从文件的某一位置开始写入rwd.seek(start);finished += info.getFinished();if (connection.getResponseCode() == 206) {//文件部分下载,返回码为206InputStream is = connection.getInputStream();byte[] buffer = new byte[1024 * 4];int len;while ((len = is.read(buffer)) != -1) {//写入文件rwd.write(buffer, 0, len);finished += len;info.setFinished(finished);//更新界面显示Message msg = new Message();msg.what = 0x123;msg.arg1 = info.getLength();msg.arg2 = info.getFinished();handler.sendMessage(msg);//停止下载if (info.isStop()) {info.setDownLoading(false);//保存此次下载的进度helper.updateData(db, info);db.close();return;}}//下载完成info.setDownLoading(false);helper.updateData(db, info);db.close();}} catch (Exception e) {e.printStackTrace();} finally {if (connection != null) {connection.disconnect();}try {if (rwd != null) {rwd.close();}} catch (IOException e) {e.printStackTrace();}}}/*** 首先开启一个线程去获取要下载文件的大小(长度)*/private void getLength() {HttpURLConnection connection = null;try {//连接网络URL url = new URL(info.getUrl());connection = (HttpURLConnection) url.openConnection();connection.setRequestMethod("GET");connection.setConnectTimeout(3000);int length = -1;if (connection.getResponseCode() == 200) {//网络连接成功//获得文件长度length = connection.getContentLength();}if (length <= 0) {//连接失败return;}//创建文件保存路径File dir = new File(DownLoaderManger.FILE_PATH);if (!dir.exists()) {dir.mkdirs();}info.setLength(length);} catch (Exception e) {e.printStackTrace();} finally {//释放资源try {if (connection != null) {connection.disconnect();}} catch (Exception e) {e.printStackTrace();}}}/*** 更新进度*/private Handler handler = new Handler() {@Overridepublic void handleMessage(Message msg) {switch (msg.what) {case 0x123:if (listener != null) {listener.updateProgress(msg.arg1, msg.arg2);}break;}}};
}

七:下载流程—>首先获取要下载文件的总长度—>然后指定从上次结束的位置开始下载文件。客官阅读需仔细哦,精华都在注释里面哦!个人认为重点部分如下两个:

//设置下载位置(从服务器上取要下载文件的某一段)
connection.setRequestProperty("Range", "bytes=" + start + "-" + info.getLength());//设置下载范围RandomAccessFile rwd = new RandomAccessFile(file, "rwd");
//从文件的某一位置开始写入
rwd.seek(start);

八:上面做了一系列准备工作之后,就可以正式开始下载了让我们一起来瞧瞧

1.给主布局界面放两个按钮,来开始/暂停/重新下载

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:id="@+id/activity_main"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"android:paddingBottom="@dimen/activity_vertical_margin"android:paddingLeft="@dimen/activity_horizontal_margin"android:paddingRight="@dimen/activity_horizontal_margin"android:paddingTop="@dimen/activity_vertical_margin"tools:context="com.azhong.downloader.MainActivity"><com.azhong.downloader.view.NumberProgressBar
        android:id="@+id/pb"android:layout_width="match_parent"android:layout_height="wrap_content" /><Button
        android:id="@+id/start"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginTop="16dp"android:text="开始下载" /><Button
        android:id="@+id/restart"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginTop="10dp"android:text="重新下载" />
</LinearLayout>

2.关于NumberProgressBar的使用可以移驾至这里
3.记得在清单文件中加入 网络访问和内存读写权限哦!
4.既然我们封装了那么久,那肯定用起来就会很简单了

public class MainActivity extends AppCompatActivity implements OnProgressListener {private NumberProgressBar pb;//进度条private DownLoaderManger downLoader = null;private FileInfo info;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);pb = (NumberProgressBar) findViewById(R.id.pb);final Button start = (Button) findViewById(R.id.start);//开始下载final Button restart = (Button) findViewById(R.id.restart);//重新下载final DbHelper helper = new DbHelper(this);downLoader = DownLoaderManger.getInstance(helper, this);info = new FileInfo("Kuaiya482.apk", "http://downloadz.dewmobile.net/Official/Kuaiya482.apk");downLoader.addTask(info);start.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {if (downLoader.getCurrentState(info.getUrl())) {downLoader.stop(info.getUrl());start.setText("开始下载");} else {downLoader.start(info.getUrl());start.setText("暂停下载");}}});restart.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {downLoader.restart(info.getUrl());start.setText("暂停下载");}});}@Overridepublic void updateProgress(final int max, final int progress) {pb.setMax(max);pb.setProgress(progress);}
}

九:断点下载的知识点在文章开头已经给出,剩下的都是加入了自己的逻辑处理和代码封装。感兴趣的伙伴们一定要自己动手尝试着去写,不然你以为你看了一遍会了其实到后来就完全不会了……Demo下载传送门

Android网络编程之——文件断点下载(暂停/继续/重新下载)相关推荐

  1. Android网络编程只局域网传输文件

    Android网络编程只局域网传输文件 首先创建一个socket管理类,该类是传输文件的核心类,主要用来发送文件和接收文件 具体代码如下: ```java1 package com.jiao.file ...

  2. 【Android】Android网络编程概述

    Android网络编程概述 原文来自:http://blog.csdn.net/kieven2008/article/details/8210737 首先,应该了解的几个问题: 1)Android平台 ...

  3. Android网络编程http派/申请服务

    最近的研究Android网络编程知识,这里有一些想法,今晚学习.与您分享. 在实际的应用程序的开发非常需要时间appserver请求数据,那么app怎样发送请求呢?以下的代码就是当中的一种情况.使用H ...

  4. Kotlin第五章: android网络编程

    1. Android网络编程 OkHttp OkHttp是一个高效的HTTP客户端,它的横空出世,让其他的网络请求框架都变得黯然失色. Retrofit Retrofit是一个基于OkHttp的RES ...

  5. Android网络编程(一)

    Android网络编程概述 首先,应该了解的几个问题: 1)Android平台网络相关API接口 a) java.net.*(标准Java接口) java.net.*提供与联网有关的类,包括流.数据包 ...

  6. 腾讯T3亲自教你!2021年Android网络编程总结篇,最强技术实现

    前言 Android常用知识体系是什么鬼?所谓常用知识体系,就是指对项目中重复使用率较高的功能点进行梳理.注意哦,不是Android知识体系. 古语道:学而不思则罔,思而不学则殆.如果将做项目类比为& ...

  7. 基于Http协议的Android网络编程

    之前写过一篇Android网络编程<浅谈android网络编程>,随着了解了更多Android知识,我意识到HttpClient已经不推荐使用了,更是在Android 6.0中被废弃了,原 ...

  8. Android网络编程系列 一 Socket抽象层

    在<Android网络编程>系列文章中,前面已经将Java的通信底层大致的描述了,在我们了解了TCP/IP通信族架构及其原理,接下来我们就开始来了解基于tcp/ip协议层的Socket抽象 ...

  9. 【Android 应用开发】Android 网络编程 API笔记 - java.net 包 权限 地址 套接字 相关类 简介

    Android 网络编程相关的包 : 9 包, 20 接口, 103 类, 6 枚举, 14异常; -- Java包 : java.net 包 (6接口, 34类, 2枚举, 12异常); -- An ...

  10. 【Android 应用开发】Android 网络编程 API笔记 - java.net 包相关 接口 api

    Android 网络编程相关的包 : 9 包, 20 接口, 103 类, 6 枚举, 14异常; -- Java包 : java.net 包 (6接口, 34类, 2枚举, 12异常); -- An ...

最新文章

  1. AI一分钟 | 豪华太空酒店预计2022年前开业;彭蕾卸任蚂蚁金服董事长,井贤栋接任;京东推出一秒能写千条文案的AI系统
  2. AODV---点点滴滴
  3. webuploader 怎么在react中_另辟蹊径搭建阅读React源码调试环境支持所有React版本细分文件断点调试...
  4. linux自动挂起什么意思,Linux中进行挂起(待机)的命令说明
  5. 通过spark-submit,本地测试SparkStreaming
  6. Facebook开源 C++11 组件库,真香!
  7. Qemu之CPU mode介绍
  8. 从保证业务不中断,看网关的“前世今生”
  9. 《数学之美》马尔科夫链的扩展-贝叶斯网络
  10. Java二维码的制作
  11. free mybatis 不生效_这些Mybatis-Plus的使用小技巧,你应该知道的!
  12. HT for Web 中Painter的介绍及用法
  13. Crazy Bird
  14. seo之html优化,SEO优化技巧之HTML优化
  15. Tablayout初始全部不选中,初始默认选中一个,初始全部选中的设置
  16. 通证估值模型-费雪模型与净现值模型详解
  17. 大恒水星相机+opencv4.0.1保存视频
  18. 1.1.7. Least Angle Regression(最小角回归)和 1.1.8. LARS Lasso
  19. std::copy与memcpy比较
  20. Tableau 巴西世界杯(八)红黄牌

热门文章

  1. java日期格式化 类_Java日期格式化(DateFormat类)
  2. 在PPAPI插件中使用Skia绘图
  3. Intellij Idea更换编程字体
  4. 第一章 批判性思维概念
  5. 我的Android进阶之旅------Android【设置】-【语言和输入法】-【语言】列表中找到相应语言所对应的列表项...
  6. mysql gis 高德_基于高德自定义地图数据的GIS矢量地图制作
  7. 机器人操作系统ROS是什么?
  8. 高性能服务器 c100k,C10K及C100K问题探讨 怎么应对大流量大并发
  9. 机器学习基石第十三讲笔记
  10. 2013 VS 2018:五年前和今天的十大数字货币大比拼