Android网络编程之——文件断点下载(暂停/继续/重新下载)
开头还是不说废话了直接进入主题吧!
一:关于断点下载所涉及到的知识点
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网络编程之——文件断点下载(暂停/继续/重新下载)相关推荐
- Android网络编程只局域网传输文件
Android网络编程只局域网传输文件 首先创建一个socket管理类,该类是传输文件的核心类,主要用来发送文件和接收文件 具体代码如下: ```java1 package com.jiao.file ...
- 【Android】Android网络编程概述
Android网络编程概述 原文来自:http://blog.csdn.net/kieven2008/article/details/8210737 首先,应该了解的几个问题: 1)Android平台 ...
- Android网络编程http派/申请服务
最近的研究Android网络编程知识,这里有一些想法,今晚学习.与您分享. 在实际的应用程序的开发非常需要时间appserver请求数据,那么app怎样发送请求呢?以下的代码就是当中的一种情况.使用H ...
- Kotlin第五章: android网络编程
1. Android网络编程 OkHttp OkHttp是一个高效的HTTP客户端,它的横空出世,让其他的网络请求框架都变得黯然失色. Retrofit Retrofit是一个基于OkHttp的RES ...
- Android网络编程(一)
Android网络编程概述 首先,应该了解的几个问题: 1)Android平台网络相关API接口 a) java.net.*(标准Java接口) java.net.*提供与联网有关的类,包括流.数据包 ...
- 腾讯T3亲自教你!2021年Android网络编程总结篇,最强技术实现
前言 Android常用知识体系是什么鬼?所谓常用知识体系,就是指对项目中重复使用率较高的功能点进行梳理.注意哦,不是Android知识体系. 古语道:学而不思则罔,思而不学则殆.如果将做项目类比为& ...
- 基于Http协议的Android网络编程
之前写过一篇Android网络编程<浅谈android网络编程>,随着了解了更多Android知识,我意识到HttpClient已经不推荐使用了,更是在Android 6.0中被废弃了,原 ...
- Android网络编程系列 一 Socket抽象层
在<Android网络编程>系列文章中,前面已经将Java的通信底层大致的描述了,在我们了解了TCP/IP通信族架构及其原理,接下来我们就开始来了解基于tcp/ip协议层的Socket抽象 ...
- 【Android 应用开发】Android 网络编程 API笔记 - java.net 包 权限 地址 套接字 相关类 简介
Android 网络编程相关的包 : 9 包, 20 接口, 103 类, 6 枚举, 14异常; -- Java包 : java.net 包 (6接口, 34类, 2枚举, 12异常); -- An ...
- 【Android 应用开发】Android 网络编程 API笔记 - java.net 包相关 接口 api
Android 网络编程相关的包 : 9 包, 20 接口, 103 类, 6 枚举, 14异常; -- Java包 : java.net 包 (6接口, 34类, 2枚举, 12异常); -- An ...
最新文章
- AI一分钟 | 豪华太空酒店预计2022年前开业;彭蕾卸任蚂蚁金服董事长,井贤栋接任;京东推出一秒能写千条文案的AI系统
- AODV---点点滴滴
- webuploader 怎么在react中_另辟蹊径搭建阅读React源码调试环境支持所有React版本细分文件断点调试...
- linux自动挂起什么意思,Linux中进行挂起(待机)的命令说明
- 通过spark-submit,本地测试SparkStreaming
- Facebook开源 C++11 组件库,真香!
- Qemu之CPU mode介绍
- 从保证业务不中断,看网关的“前世今生”
- 《数学之美》马尔科夫链的扩展-贝叶斯网络
- Java二维码的制作
- free mybatis 不生效_这些Mybatis-Plus的使用小技巧,你应该知道的!
- HT for Web 中Painter的介绍及用法
- Crazy Bird
- seo之html优化,SEO优化技巧之HTML优化
- Tablayout初始全部不选中,初始默认选中一个,初始全部选中的设置
- 通证估值模型-费雪模型与净现值模型详解
- 大恒水星相机+opencv4.0.1保存视频
- 1.1.7. Least Angle Regression(最小角回归)和 1.1.8. LARS Lasso
- std::copy与memcpy比较
- Tableau 巴西世界杯(八)红黄牌
热门文章
- java日期格式化 类_Java日期格式化(DateFormat类)
- 在PPAPI插件中使用Skia绘图
- Intellij Idea更换编程字体
- 第一章 批判性思维概念
- 我的Android进阶之旅------Android【设置】-【语言和输入法】-【语言】列表中找到相应语言所对应的列表项...
- mysql gis 高德_基于高德自定义地图数据的GIS矢量地图制作
- 机器人操作系统ROS是什么?
- 高性能服务器 c100k,C10K及C100K问题探讨 怎么应对大流量大并发
- 机器学习基石第十三讲笔记
- 2013 VS 2018:五年前和今天的十大数字货币大比拼