用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. ...
随机推荐
- Python json使用
转自:https://www.cnblogs.com/wangyayun/p/6699184.html?utm_source=tuicool&utm_medium=referral 使用Pyt ...
- spark优化之临时目录
官方是这样说的: Directory to use for "scratch" space in Spark, including map output files and RDD ...
- 关于日期转换的知识点(SimpleDateFormat)
这篇文章不是系统的学习,是阅读一些文章,然后总结汇总的. 一:SimpleDateFormat类 1.介绍 SimpleDateFormat 是一个以国别敏感的方式格式化和分析数据的具体类. 它允许格 ...
- 010 innerHtml的使用
1.程序 <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <titl ...
- 004.Autofs自动挂载
一 安装autofs [root@imxhy data]# yum -y install autofs 二 编辑自动挂载相关配置 2.1 修改master [root@imxhy ~]# vi /et ...
- SpringBoot详细研究-03系统集成
据说杰克船长被黑客盗片了,看来信息安全依然任重而道远,本文以此为引子,来介绍下spring boot对于系统集成方面的支持. Spring Security提供一套安全框架,通过IOC和AOP来实现安 ...
- 手把手教你做爬虫---基于NodeJs
前言: 趁着北京今儿天气格外的蓝,我觉得我得干点什么,于是乎,卷起袖子,整理一下最近做爬虫的那些事儿. 目标:爬取北京大学软件与微电子学院的所有新闻,并将内容及图片存储到本地. 设计思路:经过对北京大 ...
- 什么情况下,会用到fiddler或者charles?
有的页面,比如设限制的html页面,比如原生页面,只能在手机APP里面查看,无法在电脑浏览器中打开查看,这时候,需要用fiddler抓包来查看返回数据,定位问题.
- 信号量Semaphore的使用
一.概念 Semaphore是一个计数信号量,常用于限制可以访问某些资源(物理或逻辑的)线程数目. 一个信号量有且仅有3种操作,且它们全部是原子的:初始化.增加和减少 增加可以为一个进程解除阻塞: 减 ...
- android.intent.category.DEFAULT
我们需要什么时候加android.intent.category.DEFAULT呢? 1.要弄清楚这个问题,首先需要弄明白什么是implicit(隐式) intent什么是explicit(显示) i ...