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 ...
随机推荐
- php回溯
$sl = debug_backtrace(); 返回的$sl 是一个二维数组 包含如下元素: function string 当前的函数名,参见: __FUNCTION__. line intege ...
- [转]Java 对象锁-synchronized()与线程的状态与生命周期
线程的状态与生命周期 Java 对象锁-synchronized() ? 1 2 3 4 synchronized(someObject){ //对象锁 } 对象锁的使用说明: 1.对象锁的返 ...
- Tasker, Android系统增强神器, 变量汇总
http://tasker.dinglisch.net/userguide_summary.html#variables.html http://tasker.dinglisch.net/usergu ...
- PEM DAC note
开发指南V1.0库函数版本,PWM DAC实验 350页 STM32 的定时器最快的计数频率是72Mhz,8 为分辨率的时候,PWM 频率为72M/256=281.25Khz.如果是1阶RC滤波,则要 ...
- 电脑硬件天梯图—CPU、显卡、主板
看到许多玩家对电脑的配置一点都不懂,这里特地制作了最新的硬件天梯图--CPU,显卡,主板,让大家对电脑硬件孰优孰劣有个一目了然的了解. 看不清楚的情点击小图看大图. 首先是CPU天梯图: 其次是显卡天 ...
- 计蒜之道 初赛 第三场 题解 Manacher o(n)求最长公共回文串 线段树
腾讯手机地图 腾讯手机地图的定位功能用到了用户手机的多种信号,这当中有的信号的作用范围近.有的信号作用的范围则远一些.有的信号相对于用户在不同的方位强度是不同的,有的则是在不论什么一个方向上信号强度都 ...
- 判断openfire用户的状态
/** * 判断openfire用户的状态 * 说明 :必须要 openfire加载 presence 插件,同时设置任何人都可以访问 * /status?jid=user1@my.openfire. ...
- [Android Pro] Android 必知必会-使用 supportV4 的 RoundedBitmapDrawable 实现圆角
RoundedBitmapDrawable 是 supportV4 下的一个类,有了它,显示圆角和圆形图片的情况下就不需要额外的第三方类库了,还能和各种图片加载库配合使用. 背景 今天无意间看到一段实 ...
- mysql中避免使用保留字和关键字做列的名字
设计数据表时,应尽量避免使用MySQL的关键字和保留字作为表名或列名. 比如key和keys为保留字,如果不小心使用关键字或者保留字作为列名字,执行下面的语句会出现语法错误: select * fro ...
- c#抓去网页
c#利用WebClient和WebRequest获取网页源代码的比较 2011-11-28 10:26:42 我来说两句 收藏 我要投稿 C#中一般是可以利用WebClient类和WebReq ...