概述

实现App常见下载公共 支持通知栏显示 支持 暂停、取消功能,使用Service、AsyncTask实现异步下载。特点简单、实用、方便源码扩展修改

详细

一、准备工作

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异步下载的更多相关文章

  1. Android异步下载图片并且缓存图片到本地

    Android异步下载图片并且缓存图片到本地 在Android开发中我们经常有这样的需求,从服务器上下载xml或者JSON类型的数据,其中包括一些图片资源,本demo模拟了这个需求,从网络上加载XML ...

  2. Android异步下载网络图片

    最近新做的一个项目,里面需要下载网络上的图片,并显示在UI界面上,学Android有个常识,就是Android中在主线程中没法直接更新UI的,要想更新UI必须另外开启一个线程来实现,当开启的线程完成图 ...

  3. Android 异步下载

    package com.example.demo1; import java.io.File; import java.io.FileOutputStream; import java.io.IOEx ...

  4. Android多线程分析之五:使用AsyncTask异步下载图像

    Android多线程分析之五:使用AsyncTask异步下载图像 罗朝辉 (http://www.cnblogs.com/kesalin) CC 许可,转载请注明出处 在本系列文章的第一篇<An ...

  5. Android多线程分析之一:使用Thread异步下载图像

    Android多线程分析之一:使用Thread异步下载图像 罗朝辉 (http://www.cnblogs.com/kesalin) CC 许可,转载请注明出处   打算整理一下对 Android F ...

  6. android AsyncTask异步下载并更新进度条

    AsyncTask异步下载并更新进度条    //如果不是很明白请看上篇文章的异步下载 AsyncTask<String, Integer, String> 第一个参数:String 传入 ...

  7. Android项目实战(三十一):异步下载apk文件并安装(非静默安装)

    前言: 实现异步下载apk文件 并 安装.(进度条对话框显示下载进度的展现方式) 涉及技术点: 1.ProgressDialog   进度条对话框  用于显示下载进度 2.AsyncTask     ...

  8. android开发步步为营之67:使用android开源项目android-async-http异步下载文件

    android-async-http项目地址 https://github.com/loopj/android-async-http.android-async-http顾名思义是异步的http请求, ...

  9. Android多线程分析之中的一个:使用Thread异步下载图像

    Android多线程分析之中的一个:使用Thread异步下载图像 罗朝辉 (http://blog.csdn.net/kesalin) CC 许可.转载请注明出处 打算整理一下对 Android Fr ...

随机推荐

  1. nodejs中间件拦截,express不登录无法进入后台页面

    22.设置拦截 只有登录才能进入到后台页面,不登录无法进入 如果登陆成功, 写入session, 参数 uid uid=123dsfjksldfjsl 检测登陆, 请求中 session 是否包含 u ...

  2. Programmable current source requires no power supply

    Engineering labs are usually equipped with various power supplies, voltmeters, function generators, ...

  3. find命令专辑

    find命令使用技巧 查找文件,移动到某个目录 使用find和xargs 15条 linux Find 命令实际使用方法 find 命令用法 find命令使用经验 find用法小结 find与xarg ...

  4. Gulp插件less的使用

    1.创建:gulpfile.js var gulp = require('gulp'), less = require('gulp-less'); gulp.task('default', funct ...

  5. 单击行,自己主动选中当前行中的单选框button

    需求:单击行,自己主动选中当前行中的单选框button. aspx页面: <asp:Repeater ID="rptRecordList" runat="serve ...

  6. Android:手把手带你深入剖析 Retrofit 2.0 源码

    前言 在Andrroid开发中,网络请求十分常用 而在Android网络请求库中,Retrofit是当下最热的一个网络请求库 今天,我将手把手带你深入剖析Retrofit v2.0的源码,希望你们会喜 ...

  7. 【iOS开发-90】CALayer图层:自己定义图层,图层的一些动画

    (1)效果 (2)代码 http://download.csdn.net/detail/wsb200514/8261547 (3)总结 --能够自己定义图层,尤其须要对图片进行圆角裁剪. --图层的动 ...

  8. UVA 11107(Life Forms-后缀数组+二分)

    Problem C: Life Forms You may have wondered why most extraterrestrial life forms resemble humans, di ...

  9. Video Tag Test

    --> Video Tag Test Your browser does not support the audio element.

  10. 百度、淘宝、腾讯三大巨头HTML页面有何高招?

    众所周知用html5新增标签布局不光可以使页面更具有可读性,也能使代码更清晰规范,但是兼容性成为了首要的问题,如何解决也是问题的关键. [兼容HTML5方案] 百度贴吧,百度图片的实现: <!- ...