Android异步下载
技术:Android
概述
实现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
一起学习,一起进步
本实例支付的费用只是购买源码的费用,如有疑问欢迎在文末留言交流,如需作者在线代码指导、定制等,在作者开启付费服务后,可以点击“购买服务”进行实时联系,请知悉,谢谢
手机上随时阅读、收藏该文章 ?请扫下方二维码