用Service实现断点下载
整体的思路:
在下载文件时,将进度写入数据库,同一时候通知该ContentProvider的观察者更新页面,这个通知过程不要太频繁。我设置了10次,否则页面会灰常卡。
假设异常中断(网络中断或程序被kill)也没有关系。由于数据库中有记录,仅仅要从该文件的断点位置继续下载就能够了。关键在于一切以数据库为准
就能够了。
同一时候要注意的是:
1、自始至终处理的都是同一个PO对象,没有直接用类的成员变量,由于下次启动线程。成员变量会变化,导致诡异的下载文件不正确应。
2、启动线程后,将该线程保存进static类变量 downloaders 里,方便在Service类外进行停止线程。
3、由于有一个或多个下载进度的页面。所以在下载更新数据库的同一时候。进行了通知观察者的操作。当然也能够有其它的方法,比方,
1)在Activity里加入一个线程时刻扫描数据库等等,只是感觉没有这个好。
2)也实用更新进度的时候,不断发广播的方式,在Activity中注冊广播接收者更新页
大家有更好的办法请回复。
红色字体部分为关键。其它都是浮云。
。
/**
*
* 因为该Service用于多线程下载文件,须要确保原子性。一直处理一个DownLoadFilePO对象
*
* <p>detailed comment
* @see
* @since 1.0
*/
public class DownLoadService extends Service {
private static final String TAG = "DownLoadFileService";
private String downloadUrl;
private boolean showToast;
public static Map<String, DownLoadThread> downloaders = new HashMap<String, DownLoadThread>();
@Override
public IBinder onBind(Intent arg0) {
return null;
}
@Override
public void onCreate() {
//仅仅运行一次
super.onCreate();
}
@Override
@Deprecated
public void onStart(Intent intent, int startId) {
super.onStart(intent, startId);
if (intent == null) {
return;
}
downloadUrl = intent.getStringExtra("downloadUrl");
showToast = intent.getBooleanExtra("showToast", false);
DownLoadThread downLoadThread = new DownLoadThread(downloadUrl);
Thread thread = new Thread(downLoadThread);
thread.start();
}
/**
*
* 下载线程
*
* <p>detailed comment
* @see
* @since 1.0
*/
public class DownLoadThread implements Runnable {
String url;
boolean downloading = true;
DownLoadThread(String downloadUrl) {
this.url = downloadUrl;
}
/**
* 终止线程
*/
public void stop() {
this.downloading = false;
}
@Override
public void run() {
//查看是否已经在下载
DownLoadFilePO po = queryByDownLoadUrl(url);
if (po != null) {
if (showToast) {
showToast(getResources().getString(R.string.this_file_is_downloaded));
} else {
downloaders.put(downloadUrl, this);
showToast(getResources().getString(R.string.this_file_begin_download));
download(po);
}
} else {
po = init(url);
initProgress(po);
downloaders.put(downloadUrl, this);
download(po);
}
}
/**
* 下载
*/
private void download(DownLoadFilePO po) {
HttpURLConnection connection = null;
RandomAccessFile randomAccessFile = null;
InputStream is = null;
try {
URL url = new URL(downloadUrl);
connection = (HttpURLConnection) url.openConnection();
connection.setConnectTimeout(5000);
connection.setRequestMethod("GET");
// 设置远程文件的下载范围。格式为Range:bytes x-y;
connection.setRequestProperty("Range",
"bytes=" + po.getCurrent_size() + "-" + po.getTotal_size());
//设置本地文件的下载開始位置
File localFile = new File(po.getFile());
randomAccessFile = new RandomAccessFile(localFile, "rwd");
randomAccessFile.seek(po.getCurrent_size());
is = connection.getInputStream();
byte[] buffer = new byte[1024000];
int length = -1;
int count = 0;
while ((length = is.read(buffer)) != -1) {
randomAccessFile.write(buffer, 0, length);
// 更新数据库中的下载信息
po.setCurrent_size(po.getCurrent_size() + length);
updateProgress(po);
// 用消息将下载信息传给进度条,对进度条进行更新
count++;
if (count % 10 == 0) {
getContentResolver().notifyChange(ConstantUtil.uri, null);//假设改变数据。则通知全部人
Log.v(TAG, po.getName() + "=======下载进度======" + po.getCurrent_size());
}
if (!downloading) {
Log.v(TAG, po.getName() + "=======暂停====" + po.getCurrent_size());
downloaders.remove(po.getDownloadUrl());
return;
}
}
//下载完毕
if (po.getCurrent_size() == po.getTotal_size()) {
finishProgress(po);
}
downloaders.remove(po.getDownloadUrl());
} catch (Exception e) {
getContentResolver().notifyChange(ConstantUtil.uri, null);//假设改变数据,则通知全部人
this.stop();
e.printStackTrace();
} finally {
try {
is.close();
randomAccessFile.close();
connection.disconnect();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
/**
* 初始化
*/
private DownLoadFilePO init(String downloadUrl) {
DownLoadFilePO po = new DownLoadFilePO();
try {
if (!FileUtil.checkFileDir()) {
return null;
}
URL url = new URL(downloadUrl);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setConnectTimeout(5000);
connection.setRequestMethod("GET");
int fileSize = connection.getContentLength();
//总大小
String fileName = FileUtil.getFileNameByUrl(downloadUrl);
try {
fileName = URLDecoder.decode(fileName, "UTF-8");
} catch (UnsupportedEncodingException e) {
Log.e(TAG, e.getMessage());
}
File localFile = new File(ConstantUtil.downloadFileDir + fileName);
//推断同名文件已经存在。如存在同名的文件。需改动文件名 sample.mp4 ==>sample(1).mp4
int i = 1;
while (localFile.exists()) {
int index = fileName.lastIndexOf(".");
fileName = fileName.substring(0, index) + "(" + i + ")"
+ fileName.substring(index, fileName.length());
localFile = new File(ConstantUtil.downloadFileDir + fileName);
i++;
}
localFile.createNewFile();
i = 0;
// }
// 本地訪问文件
RandomAccessFile accessFile = new RandomAccessFile(localFile, "rwd");
accessFile.setLength(fileSize);
accessFile.close();
connection.disconnect();
po.setName(fileName);
po.setDownloadUrl(downloadUrl);
po.setCurrent_size(0L);
po.setTotal_size(fileSize);
po.setFile(localFile.getAbsolutePath());
} catch (Exception e) {
e.printStackTrace();
}
return po;
}
/**
* 向数据库中插入初始化数据
*/
private void initProgress(DownLoadFilePO po) {
ContentValues values = new ContentValues();
values.put(DataBaseUtil.DOWNLOAD_FILE_NAME, po.getName());
values.put(DataBaseUtil.CREATE_FILE_DATE, new Date().toString());
values.put(DataBaseUtil.DOWNLOAD_FILE_TOTAL_SIZE, po.getTotal_size());
values.put(DataBaseUtil.DOWNLOAD_FILE_CURRENT_SIZE, 0);
values.put(DataBaseUtil.DOWNLOAD_FINISHED, false);
values.put(DataBaseUtil.DOWNLOAD_URL, po.getDownloadUrl());
values.put(DataBaseUtil.DONWLOAD_FILE_PATH, po.getFile());
this.getContentResolver().insert(ConstantUtil.uri, values); //向ContentProvider插入数据
}
/**
*
* 更新进度
*
*<p>detail comment
*@see
*@since
*
*/
private void updateProgress(DownLoadFilePO po) {
ContentValues values = new ContentValues();
values.put(DataBaseUtil.DOWNLOAD_FILE_CURRENT_SIZE, po.getCurrent_size());
this.getContentResolver().update(ConstantUtil.uri, values,
DataBaseUtil.DOWNLOAD_URL + "=?
", new String[] { po.getDownloadUrl() });
}
/**
*
* 完毕下载
*
*<p>detail comment
*@param currentSize
*@see
*@since
*
*/
private void finishProgress(DownLoadFilePO po) {
ContentValues values = new ContentValues();
values.put(DataBaseUtil.DOWNLOAD_FILE_CURRENT_SIZE, po.getTotal_size());
values.put(DataBaseUtil.DOWNLOAD_FINISHED, true);
this.getContentResolver().update(ConstantUtil.uri, values,
DataBaseUtil.DOWNLOAD_URL + "=?
", new String[] { po.getDownloadUrl() });
getContentResolver().notifyChange(ConstantUtil.uri, null);
}
/**
*
* 查看该url是否在下载
*
*<p>detail comment
*@param url
*@return
*@see
*@since
*
*/
private DownLoadFilePO queryByDownLoadUrl(String url) {
Cursor cursor = this.getContentResolver().query(
ConstantUtil.uri,
new String[] { DataBaseUtil.DOWNLOAD_FILE_NAME,
DataBaseUtil.DOWNLOAD_FILE_CURRENT_SIZE,
DataBaseUtil.DOWNLOAD_FILE_TOTAL_SIZE, DataBaseUtil.DONWLOAD_FILE_PATH,
DataBaseUtil.DOWNLOAD_FINISHED }, DataBaseUtil.DOWNLOAD_URL + "=?",
new String[] { url }, null);
if (cursor.moveToNext()) {
DownLoadFilePO po = new DownLoadFilePO();
for (int i = 0; i < cursor.getCount(); i++) {
cursor.moveToPosition(i);
po.setName(cursor.getString(0));
po.setCurrent_size(cursor.getLong(1));
po.setTotal_size(cursor.getLong(2));
po.setFile(cursor.getString(3));
po.setDownloadUrl(url);
}
return po;
}
return null;
}
private void showToast(final String toast) {
Handler handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable() {
public void run() {
Toast.makeText(DownLoadService.this, toast, Toast.LENGTH_SHORT).show();
}
});
}
}
用Service实现断点下载的更多相关文章
- 安卓(android)之实现断点下载功能
一.建立实体类 1.文件实体类 package com.example.zjw.myapplication.dao; import java.io.Serializable; /** * 预下载文件实 ...
- Retrofit 2.0 超能实践(四),完成大文件断点下载
作者:码小白 文/CSDN 博客 本文出自:http://blog.csdn.net/sk719887916/article/details/51988507 码小白 通过前几篇系统的介绍和综合运用, ...
- andoid 多线程断点下载
本示例介绍在Android平台下通过HTTP协议实现断点续传下载. 我们编写的是Andorid的HTTP协议多线程断点下载应用程序.直接使用单线程下载HTTP文件对我们来说是一件非常简单的事.那么,多 ...
- Android学习笔记_15_网络通信之文件断点下载
一.断点下载原理: 使用多线程下载文件可以更快完成文件的下载,多线程下载文件之所以快,是因为其抢占的服务器资源多.如:假设服务器同时最多服务100个用户,在服务器中一条线程对应一个用户,100条线程在 ...
- 我的Android进阶之旅------>Android基于HTTP协议的多线程断点下载器的实现
一.首先写这篇文章之前,要了解实现该Android多线程断点下载器的几个知识点 1.多线程下载的原理,如下图所示 注意:由于Android移动设备和PC机的处理器还是不能相比,所以开辟的子线程建议不要 ...
- Java实现多线程断点下载(下载过程中可以暂停)
线程可以理解为下载的通道,一个线程就是一个文件的下载通道,多线程也就是同时开启好几个下载通道.当服务器提供下载服务时,使用下载者是共享带宽的,在优先级相同的情况下,总服务器会对总下载线程进行平均分配. ...
- iOS 大文件断点下载
iOS 在下载大文件的时候,可能会因为网络或者人为等原因,使得下载中断,那么如何能够进行断点下载呢? // resumeData的文件路径 #define XMGResumeDataFile [[NS ...
- 【Java EE 学习 22 下】【单线程下载】【单线程断点下载】【多线程下载】
一.文件下载简述 1.使用浏览器从网页上下载文件,Servlet需要增加一些响应头信息 (1)response.setContentType("application/force-downl ...
- IOS 断点下载
// // ViewController.m // UI4_断点下载 // // Created by qianfeng on 15/8/19. // Copyright (c) 2015年 ZBC. ...
随机推荐
- 我们在部署 HTTPS 网站时,该如何选择SSL证书?
我们在部署 HTTPS 网站时,该如何选择SSL证书? 首次部署HTTPS网站的同学对选择什么样的SSL证书多多少少都有点迷茫. 这里考虑的因素确实不少:是否支持多域名.泛域名,价格,信息泄露的保额, ...
- mysql5.6.34在默认配置文件修改字符集为utf8后重启mysql服务没效果
1:事情是这样的,我下载了一个mysql5.6.34版本(windows版本的),下载下来后里面只有个my-default.ini,然后我就直接在my-default.ini 里面配置basedir, ...
- Dynamic Rankings || 动态/静态区间第k小(主席树)
JYF大佬说,一星期要写很多篇博客才会有人看 但是我做题没有那么快啊QwQ Part1 写在前面 区间第K小问题一直是主席树经典题=w=今天的重点是动态区间第K小问题.静态问题要求查询一个区间内的第k ...
- TFC2017 腾讯Web前端大会参会小结
简述 上周有幸参加TFC腾讯Web前端大会,见识了各路前端大神的精彩演讲,干货满满的.会议流程分为上午主会场,以及下午的三个分会场.分享的主题涵盖Web新技术.Node.js.框架.工程化. 图形处理 ...
- 转:Spring中事物管理
1.什么是事务? 事务是逻辑上的一组操作,这组操作要么全部成功,要么全部失败 2.事物具有四大特性ACID 说到事务,就不得不说其4大特性,主要如下 原子性:(atomicity) 原子性指的是事务是 ...
- 【Ubuntu】Ubuntu设置和查看环境变量
[Ubuntu]Ubuntu设置和查看环境变量 转载 https://blog.csdn.net/White_Idiot/article/details/78253004 1. 查看环境变量 查 ...
- InnoDB的锁机制浅析(二)—探索InnoDB中的锁(Record锁/Gap锁/Next-key锁/插入意向锁)
Record锁/Gap锁/Next-key锁/插入意向锁 文章总共分为五个部分: InnoDB的锁机制浅析(一)-基本概念/兼容矩阵 InnoDB的锁机制浅析(二)-探索InnoDB中的锁(Recor ...
- 【Ray Tracing in One Weekend 超详解】 光线追踪1-3
学完了插值,我们来学习在场景里面添加一个立体彩色球(三维插值) 按照惯例,先看效果: Chapter4: Adding a sphere 我们又一次面临图形学的主要任务. 我们需要再次回顾coord1 ...
- 循序渐进学.Net Core Web Api开发系列【3】:WebApi开发概览
系列目录 循序渐进学.Net Core Web Api开发系列目录 本系列涉及到的源码下载地址:https://github.com/seabluescn/Blog_WebApi 一.概述 目前我们已 ...
- Redis介绍及部署在CentOS7上(一)
0.Redis目录结构 1)Redis介绍及部署在CentOS7上(一) 2)Redis指令与数据结构(二) 3)Redis客户端连接以及持久化数据(三) 4)Redis高可用之主从复制实践(四) 5 ...