Android异步下载
概述
详细
一、准备工作
1、项目运行环境AndroidStudio
3、通过Service、AsyncTask实现异步下载,并通过通知栏显示下载进度。
二、程序实现
1、工程目录

2、在AsyncTask中实现下载操作
public DownloadTask(DownloadListener listener) {
this.listener = listener;
}
/**
* 执行具体下载逻辑
* @param strings
* @return 下载状态
*/
@Override
protected Integer doInBackground(String... strings) {
InputStream is = null;
RandomAccessFile savedFile = null;
File file = null;
try {
long downloadedLength = 0; //记录已下载文件的长度
String downloadUrl = strings[0];//获取下载地址
String fileName = downloadUrl.substring(downloadUrl.lastIndexOf("/"));
String directory = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getPath();
file = new File(directory + fileName);//将文件指定下载到SD卡的Download目录下
if (file.exists()) {//判断是否已存在文件,是:取出文件大小(字节数)
downloadedLength = file.length();
}
long contentLength = getContentLength(downloadUrl);//获取待下载文件大小(字节数)
if (contentLength == 0) {//长度为0,文件异常,下载失败
return TYPE_FAILED;
} else if (contentLength == downloadedLength) {//文件长度等于已下载长度,已下载完,直接返回成功
return TYPE_SUCCESS;
}
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.addHeader("RANGE", "bytes=" + downloadedLength + "-")//断点下载,指定从哪个字节开始下载
.url(downloadUrl)
.build();
Response response = client.newCall(request).execute();
if (response != null) {
is = response.body().byteStream();
savedFile = new RandomAccessFile(file, "rw");
savedFile.seek(downloadedLength);//跳过已下载字节
byte[] bytes = new byte[1024];
int total = 0;
int len;
while ((len = is.read(bytes)) != -1) {
if (isCanceled) {//判断是否有取消操作
return TYPE_CANCELED;
} else if (isPaused) {//判断是否有暂停操作
return TYPE_PAUSED;
} else {
total += len;
savedFile.write(bytes, 0, len);
//计算已下载百分比
int progress = (int) ((total + downloadedLength) * 100 / contentLength);
publishProgress(progress);
}
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
} catch (Exception e) {
e.printStackTrace();
}
}
return TYPE_FAILED;
}
/**
* 更新下载进度
* @param values
*/
@Override
protected void onProgressUpdate(Integer... values) {
int progress = values[0];
if (progress > lastProgress) {
listener.onProgress(progress);
lastProgress = progress;
}
}
/**
* 通知下载结果
* @param type
*/
@Override
protected void onPostExecute(Integer type) {
switch (type) {
case TYPE_SUCCESS:
listener.onSuccess();
break;
case TYPE_FAILED:
listener.onFailed();
break;
case TYPE_PAUSED:
listener.onPaused();
break;
case TYPE_CANCELED:
listener.onCanceled();
break;
default:
break;
}
}
public void pauseDownload() {
isPaused = true;
}
public void cancelDownload() {
isCanceled = true;
}
private long getContentLength(String downloadUrl) throws IOException {
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder().url(downloadUrl).build();
Response response = client.newCall(request).execute();
if (response != null && response.isSuccessful()) {
long contentLength = response.body().contentLength();
response.body().close();
return contentLength;
}
return 0;
}
3、使用interface观察者模式监听下载动作
public interface DownloadListener {
//当前下载进度
void onProgress(int progress);
//下载成功
void onSuccess();
//下载失败
void onFailed();
//下载暂停
void onPaused();
//下载取消
void onCanceled();
}
4、在Service中初始化AsyncTask并实例化监听
private DownloadTask downloadTask;
private String downloadUrl;
private DownloadListener downloadListener = new DownloadListener() {//创建Download实例
@Override
public void onProgress(int progress) {
//构建显示下载进度的通知,并触发通知
getNotificationManager().notify(1, getNotification("Downloading ...",progress));
}
@Override
public void onSuccess() {
downloadTask = null;
//下载成功将前台服务关闭,并创建一个下载成功的通知
stopForeground(true);
getNotificationManager().notify(1, getNotification("Download Success",-1));
Toast.makeText(DownloadService.this,"Download Success",Toast.LENGTH_SHORT).show();
}
@Override
public void onFailed() {
downloadTask = null;
//下载失败将前台服务关闭,并创建一个下载失败的通知
stopForeground(true);
getNotificationManager().notify(1, getNotification("Download Failed",-1));
Toast.makeText(DownloadService.this,"Download Failed",Toast.LENGTH_SHORT).show();
}
@Override
public void onPaused() {
downloadTask = null;
Toast.makeText(DownloadService.this,"Download Paused",Toast.LENGTH_SHORT).show();
}
@Override
public void onCanceled() {
downloadTask = null;
stopForeground(true);
Toast.makeText(DownloadService.this,"Download Canceled",Toast.LENGTH_SHORT).show();
}
};
5、创建下载进度通知栏
private Notification getNotification(String title, int progress) {
Intent intent = new Intent(this, MainActivity.class);
PendingIntent pi = PendingIntent.getActivity(this, 0, intent, 0);
NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
builder.setSmallIcon(R.mipmap.ic_launcher_round);
builder.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher));
builder.setContentIntent(pi);
builder.setContentTitle(title);
if (progress >= 0) {
//当progress大于或等0时才需要显示下载进度
builder.setContentText(progress + "%");
builder.setProgress(100, progress, false);
}
return builder.build();
}
6.创见DownloadBinder类,与外部建立连接
private DownloadBinder mBinder = new DownloadBinder(); @Override
public IBinder onBind(Intent intent) {
return mBinder;
} class DownloadBinder extends Binder{
public void startDownload(String url){
if (downloadTask == null){
downloadUrl = url;
downloadTask = new DownloadTask(downloadListener);
downloadTask.execute(downloadUrl);
startForeground(1,getNotification("Downloading ... ",0));
Toast.makeText(DownloadService.this,"Downloading ... ",Toast.LENGTH_SHORT).show();
}
} public void pauseDownload(){
if (downloadTask != null){
downloadTask.pauseDownload();
}else {
if (downloadUrl != null){
//取消下载是删除文件,关闭通知
String fileName = downloadUrl.substring(downloadUrl.lastIndexOf("/"));
String directory = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getPath();
File file = new File(directory + fileName);
if (file.exists()){
file.delete();
}
getNotificationManager().cancel(1);
stopForeground(true);
Toast.makeText(DownloadService.this,"Canceled",Toast.LENGTH_SHORT).show();
}
}
} public void cancelDownload(){
if (downloadTask != null){
downloadTask.cancelDownload();
}
}
}
7、绑定Service
private DownloadService.DownloadBinder downloadBinder;
private ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
downloadBinder = (DownloadService.DownloadBinder) iBinder;
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = new Intent(this,DownloadService.class);
startService(intent);//启动服务
bindService(intent,serviceConnection,BIND_AUTO_CREATE);//绑定服务
if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE)!= PackageManager.PERMISSION_GRANTED){
//获取读写权限
ActivityCompat.requestPermissions(MainActivity.this,new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},1);
}
}
三、运行效果
1、调用方法
public void startDownload(View view) {
if (downloadBinder == null){
return;
}
String url = "your URL (你的下载路径)";
downloadBinder.startDownload(url);
}
public void pauseDownload(View view) {
if (downloadBinder == null){
return;
}
downloadBinder.pauseDownload();
}
public void cancelDownload(View view) {
if (downloadBinder == null){
return;
}
downloadBinder.cancelDownload();
}
3、运行时的截图

四、其他补充
1、如何修改通知栏样式?
NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
builder.setSmallIcon(R.mipmap.ic_launcher_round);
builder.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher));
builder.setContentIntent(pi);
builder.setContentTitle(title);
2、不了解Service、AsyncTask?
Android Service(服务)详解·(一)相关知识点引入
Android Service(服务)详解·(二)Service基本用法
3、还有疑问?
请联系我 留言 或者 E-mail : duyangs1994@gmail.com
一起学习,一起进步
注:本文著作权归作者,由demo大师发表,拒绝转载,转载需要作者授权
Android异步下载的更多相关文章
- Android异步下载图片并且缓存图片到本地
Android异步下载图片并且缓存图片到本地 在Android开发中我们经常有这样的需求,从服务器上下载xml或者JSON类型的数据,其中包括一些图片资源,本demo模拟了这个需求,从网络上加载XML ...
- Android异步下载网络图片
最近新做的一个项目,里面需要下载网络上的图片,并显示在UI界面上,学Android有个常识,就是Android中在主线程中没法直接更新UI的,要想更新UI必须另外开启一个线程来实现,当开启的线程完成图 ...
- Android 异步下载
package com.example.demo1; import java.io.File; import java.io.FileOutputStream; import java.io.IOEx ...
- Android多线程分析之五:使用AsyncTask异步下载图像
Android多线程分析之五:使用AsyncTask异步下载图像 罗朝辉 (http://www.cnblogs.com/kesalin) CC 许可,转载请注明出处 在本系列文章的第一篇<An ...
- Android多线程分析之一:使用Thread异步下载图像
Android多线程分析之一:使用Thread异步下载图像 罗朝辉 (http://www.cnblogs.com/kesalin) CC 许可,转载请注明出处 打算整理一下对 Android F ...
- android AsyncTask异步下载并更新进度条
AsyncTask异步下载并更新进度条 //如果不是很明白请看上篇文章的异步下载 AsyncTask<String, Integer, String> 第一个参数:String 传入 ...
- Android项目实战(三十一):异步下载apk文件并安装(非静默安装)
前言: 实现异步下载apk文件 并 安装.(进度条对话框显示下载进度的展现方式) 涉及技术点: 1.ProgressDialog 进度条对话框 用于显示下载进度 2.AsyncTask ...
- android开发步步为营之67:使用android开源项目android-async-http异步下载文件
android-async-http项目地址 https://github.com/loopj/android-async-http.android-async-http顾名思义是异步的http请求, ...
- Android多线程分析之中的一个:使用Thread异步下载图像
Android多线程分析之中的一个:使用Thread异步下载图像 罗朝辉 (http://blog.csdn.net/kesalin) CC 许可.转载请注明出处 打算整理一下对 Android Fr ...
随机推荐
- PAT甲级1057. Stack
PAT甲级1057. Stack 题意: 堆栈是最基础的数据结构之一,它基于"先进先出"(LIFO)的原理.基本操作包括Push(将元素插入顶部位置)和Pop(删除顶部元素).现在 ...
- linux基础命令学习 (九)文本操作
一.head 1.语法: head [选项] [文件] 2.选项 -q 隐藏文件名 -v 显示文件名 -c<字节> 显示字节数 -n<行数> 显示的行数 3.示例 范例一:查看 ...
- 原生JavaScript---正则表达式
JavaScript 中正则的性能比想象中的低很多.能用字符串方法搞定的,尽量别用正则.------玉伯 抛开性能不谈,一起来看看正则表达式怎么用吧! 先看看JavaScript正则表达式中一些特殊字 ...
- 解决IIS 不能下载.exe.config文件的方法
IIS允许下载".config"文件 Config文件是web的配置文件,默认是不允许下载的,就算在MIME中配置“application/octet-stream”,也是下载不了 ...
- 用css让一个容器水平垂直居中
阅读目录 方法一:position加margin 方法二: diaplay:table-cell 方法三:position加 transform 方法四:flex;align-items: cente ...
- MySQL MERGE存储引擎 简介
MERGE存储引擎把一组MyISAM数据表当做一个逻辑单元来对待,让我们可以同时对他们进行查询.构成一个MERGE数据表结构的各成员MyISAM数据表必须具有完全一样的结构.每一个成员数据表的数据列必 ...
- Replace Pioneer 试用推广
Replace Pioneer: http://www.mind-pioneer.com 目前合法长期使用Replace Pioneer的唯一方法(除了购买之外): Replace Pioneer过期 ...
- 【Hibernate步步为营】--hql查询小介
HQL 是指Hibernate Query Language,它是Hibernate的查询语言,拥有一套自己的查询机制,它的查询语句和SQL非常类似.在使用的时候可以非常快上手.HQL提供了基本上SQ ...
- 数学图形(2.8)Viviani曲线
维维亚尼(Viviani , Vincenzo)意大利数学家.1622年4月5日生于托斯卡纳大区佛罗伦萨:1703年9月22日卒于佛罗伦萨. 这是一个圆柱与一个球相交而生成的曲线. #http://w ...
- BeagleBone折腾记(一):连接你的狗板
BeagleBone折腾记一连接你的狗板 准备 了解BeagleBone BeagleBone社区 所需软硬件 USB连接 TTL连接 结语 准备 了解BeagleBone BeagleBone可能一 ...