用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多个分割符split字符串
python中string自带的split不支持多个分隔符同时切分,用正则 import re line='hello,world' lineLists = re.split('[,,..??]',l ...
- Java多态概述
多态 所谓多态,实际上就是一个对象的多种状态: 下面例子中,Tiger可以看做Tiger,也可以看做Animal Cat 可以看做Cat,也可以看做Animal Dog 可以看做Dog,也可以看做A ...
- java 编译与运行
javac 编译 .java文件 javac file.java //将file.java 编译为 file.classjavac -d folder file.java //将file.java ...
- php常用的安全过滤函数
目录结构 ①常用的安全函数有哪些: ②这些函数的作用: ③函数的用法: ④举例说明: ⑤参考资料: 由于越来越多的项目开始使用框架,所以,很多的程序员也不在关心安全的问题!因为框架已经帮我们几乎完美的 ...
- <转> 解决异常:IllegalStateException: Fragment <ThisFragment> is not currently in the FragmentManager
上午敲代码时出现这个问题,简单记录一下解决办法,有时间详细描述一下深层原因. 问题出现在这: @Override public void onSaveInstanceState(Bundle outS ...
- SQL Server 4
一.视图 1.创建视图 1)选中数据库中的表中的视图处,右键选择新建视图,即: 2)在弹出“添加表”对话框中,单击“表”标签,选择要添加的表,点击添加,即: 3)选中要建立联系的列名的复选框,然后拖动 ...
- 如何写django中form的测试用例
可简可繁, 可插库,可字符, 要测试valid,也要测试invalid, 可用csrf,也可用context. 放一个全面的, 实践中,找一个最优的组合就好. class NewTopicTests( ...
- webstorm减少内存占用
首先,按照我说的设置之后要重启才行. 在项目里找到不需要监听的文件夹右键:Mark Directory As => Cancel Exclusion 然后重启,嘿嘿,成功了!
- String、Date和Timestamp的互转
begin 2018年8月17日19:09:49 String.Date和Timestamp的互转 String和Date的互转 关于String和Date的互转,在java8后会有不同.因为java ...
- Java NIO -2
NIO http://www.cnblogs.com/puyangsky/p/5840873.html -- 操作系统与 Java 基于流的 I/O模型有些不匹配.操作系统要移动的是大块数据(缓冲区) ...