用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. ...
随机推荐
- 为什么尽量别用 setInterval
为什么尽量别用setInterval 在开发一个在线聊天工具时,经常会有过多少毫秒就重复执行一次某操作的需求.“没问题”,大家都说,“用setInterval好了.”我觉得这个点子很糟糕. 原因之 ...
- java innerclasses(内部类)
可以将一个类定义在另一个类的内部,这就是内部类 创建内部类的方式---把类的定义置于外部类的里面 典型的情况是,外部类将有一个方法,该方法返回一个指向内部类的引用,就像在to()和contents() ...
- 【招聘】这一次,我们Hold住了世界杯
作为国内最大的云计算服务商,阿里云在视频领域拥有绝对的技术优势,全球范围内拥有1500多个CDN节点,带宽储备120多T,不仅为优酷.CNTV.CCTV5提供技术支撑,还承担了全网70%的世界杯流量. ...
- 4.自定义数据《jquery实战》
4.4 元素中的存储自定义数据 data([key],[value]) 在元素上存放数据,返回jQuery对象. key (String) 存储的数据名. key,value (String,Any) ...
- linux下如何查看命令的绝对路径
在linux上经常使用ls,grep,vi等命令,如何查看这些命令的绝对路径呢? 通过whereis/which 就可以啦,但是这两个命令之间还是有一些区别.网上查了一下资料,解释如下: which ...
- zabbix agent配置文件记录
一.无论主动还是被动模式都要配置server和linstenPort 二.若要设置主动模式那么要添加ServerActive,若不添加则默认为被动模式
- Linux性能优化之磁盘优化(三)
前言 关于本章内容,设计的东西比较多.这里会有关于文件系统.磁盘.CPU等方面的知识,以及涉及到关于这方面的性能排查等. 术语 文件系统通过缓存和缓冲以及异步I/O等手段来缓和磁盘的延时对应用程序的影 ...
- sqlite读写
#coding=utf-8 import sqlite3 import os #创建数据库和游标 if os.path.exists(' test.db'): conn=sqlite3.connect ...
- js控制手机端字体大小rem
//得到手机屏幕的宽度 let htmlWidth = document.documentElement.clientWidth || document.body.clientWidth; if(ht ...
- [代码审计]云ec电商系统代码审计
0x00 前言 看了一下博客内最新的文章,竟然是3月28号的,一个多月没写文章了,博客都长草了. 主要是临近毕业,事情繁多,也没有啥时间和心情静下来写.. 不过现在的话,毕业的东西告一段落了,几乎没啥 ...