Android下载进度监听和通知的处理详解

本文实例为大家分享了Android下载进度监听和通知的具体代码,供大家参考,具体内容如下

下载管理器

关于下载进度的监听,这个比较简单,以apk文件下载为例,需要处理3个回调函数,分别是:

1.下载中
2.下载成功
3.下载失败

因此对应的回调接口就有了:

public interface DownloadCallback { /** * 下载成功 * @param file 目标文件 */ void onComplete(File file); /** * 下载失败 * @param e */ void onError(Exception e); /** * 下载中 * @param count 总大小 * @param current 当前下载的进度 */ void onLoading(long count, long current); }

接下来就是线程池的管理了,当然你也可以直接使用Executors工具类中提供的几个静态方法来创建线程池,这里我是手动创建线程池的,代码如下:

public class ThreadManager { private static ThreadPool mThreadPool; /** * 获取线程池 * * @return */ public static ThreadPool getThreadPool() { if (null == mThreadPool) { synchronized (ThreadManager.class) { if (null == mThreadPool) { // cpu个数 int cpuNum = Runtime.getRuntime().availableProcessors(); //线程个数 int count = cpuNum * 2 + 1; mThreadPool = new ThreadPool(count, count, 0); } } } return mThreadPool; } public static class ThreadPool { int corePoolSize;// 核心线程数 int maximumPoolSize;// 最大线程数 long keepAliveTime;// 保持活跃时间(休息时间) private ThreadPoolExecutor executor; /** * 构造方法初始化 * * @param corePoolSize * @param maximumPoolSize * @param keepAliveTime */ private ThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime) { this.corePoolSize = corePoolSize; this.maximumPoolSize = maximumPoolSize; this.keepAliveTime = keepAliveTime; } private static final ThreadFactory sThreadFactory = new ThreadFactory() { private final AtomicInteger mCount = new AtomicInteger(1); public Thread newThread(Runnable r) { return new Thread(r, "ThreadManager #" + mCount.getAndIncrement()); } }; /** * 执行线程任务 * * @param r */ public void execute(Runnable r) { //参1:核心线程数;参2:最大线程数;参3:保持活跃时间(休息时间);参4:活跃时间单位;参5:线程队列;参6:线程工厂;参7:异常处理策略 if (null == executor) { executor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(), sThreadFactory/*Executors.defaultThreadFactory()*/, new ThreadPoolExecutor.AbortPolicy()); } // 将当前Runnable对象放在线程池中执行 executor.execute(r); } /** * 从线程池的任务队列中移除一个任务 * 如果当前任务已经是运行状态了,那么就表示不在任务队列中了,也就移除失败. */ public void cancle(Runnable r) { if (null != executor && null != r) { executor.getQueue().remove(r); } } /** * 是否关闭了线程池 * @return */ public boolean isShutdown(){ return executor.isShutdown(); } /** * 关闭线程池 */ public void shutdown() { executor.shutdown(); } } }

接下来就是一个下载管理器的封装了.

public class DownloadManager { private DownloadCallback callback; private Context context; private String url; private String fileName; /** * 初始化 * @param context 上下文 * @param url 目标文件url * @param fileName 下载保存的文件名 * @param callback 下载回调函数 */ public DownloadManager(final Context context, final String url, final String fileName, DownloadCallback callback) { this.context = context; this.url = url; this.fileName = fileName; this.callback = callback; } /** * 开始下载 */ public void startDownload() { if (null == callback) return; ThreadManager.getThreadPool().execute(new Runnable() { @Override public void run() { HttpURLConnection conn = null; try { conn = (HttpURLConnection) new URL(url).openConnection(); conn.setRequestMethod("GET"); conn.setReadTimeout(5000); conn.setConnectTimeout(10000); long total = conn.getContentLength(); long curr = 0; File file = new File(PathUtils.getDirectory(context, "apk"), fileName); if (!file.exists()) { file.createNewFile(); } else { file.delete(); } FileOutputStream fos = new FileOutputStream(file); if (200 == conn.getResponseCode()) { InputStream in = conn.getInputStream(); byte[] buff = new byte[1024]; int len = 0; while ((len = in.read(buff)) != -1) { fos.write(buff, 0, len); curr += len; callback.onLoading(total, curr); } in.close(); fos.close(); if (curr == total) { callback.onComplete(file); } else { throw new Exception("curr != total"); } } else { throw new Exception("" + conn.getResponseCode()); } } catch (Exception e) { e.printStackTrace(); callback.onError(e); } finally { if (null != conn) { conn.disconnect(); } } } }); } }

涉及的工具类如下:
PathUtils

public class PathUtils { /** * 获取cache目录下的rootDir目录 * * @param context * @param rootDir * @return */ public static File getDirectory(Context context, String rootDir) { String cachePath = context.getApplicationContext().getCacheDir().getAbsolutePath(); if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()) || !Environment.isExternalStorageRemovable()) { if (Build.VERSION.SDK_INT <= 8) { cachePath = Environment.getExternalStorageDirectory().getAbsolutePath(); } else if (context.getApplicationContext().getExternalCacheDir() != null) { cachePath = context.getApplicationContext().getExternalCacheDir().getAbsolutePath(); } } File rootF = new File(cachePath + File.separator + rootDir); if (!rootF.exists()) { rootF.mkdirs(); } //修改目录权限可读可写可执行 String cmd = "chmod 777 -R " + rootF.getPath(); CmdUtils.execCmd(cmd); return rootF; } }

CmdUtils

public class CmdUtils { public static void execCmd(String cmd) { try { Runtime.getRuntime().exec(cmd); } catch (IOException e) { e.printStackTrace(); } } }

下载通知服务

同样以apk下载为例,要实现下载通知服务的话,就用到了Notification和Service,Notification用来通知下载进度并显示给用户看,Service用于后台默默的下载文件,这里我用到了IntentService,它的好处在于任务执行完毕后会自动关闭服务.同时程序用如果其他地方还想监听到下载的进度,那么可以在IntentService下载服务中通过发送广播告知进度.

ok,下面的代码可以直接用户实现apk的升级更新的操作.

public class UpdateService extends IntentService { private File apkFile; private String url; private String fileName; private NotificationCompat.Builder builderNotification; private NotificationManager updateNotificationManager; private int appNameID; private int iconID; private PendingIntent updatePendingIntent; private boolean isUpdating; public static final String ACTION_UPDATE_PROGRESS = "blog.csdn.net.mchenys.mobilesafe.ACTION_UPDATE_PROGRESS"; private Handler updateHandler = new Handler() { public void handleMessage(Message msg) { switch (msg.what) { case 0: UpdateService.this.onFailNotification(); break; case 1: UpdateService.this.downComplete(); break; } super.handleMessage(msg); } }; public UpdateService() { super("UpdateService"); } /** * 开始更新 * * @param context * @param url 更新的url * @param fileName 下载保存apk的文件名称 */ public static void startUpdate(Context context, String url, String fileName) { Intent intent = new Intent(context, UpdateService.class); intent.putExtra("url", url); intent.putExtra("fileName", fileName); context.startService(intent); } @Override protected void onHandleIntent(Intent intent) { //WorkerThread if (!this.isUpdating && intent != null) { initData(intent); initNotification(); downloadFile(true); } } /** * 初始数据 * * @param intent */ private void initData(Intent intent) { this.isUpdating = true; this.url = intent.getStringExtra("url"); this.fileName = intent.getStringExtra("fileName"); this.apkFile = new File(PathUtils.getDirectory(getApplicationContext(), "mobilesafe"), fileName); if (!this.apkFile.exists()) { try { this.apkFile.createNewFile(); } catch (IOException e) { e.printStackTrace(); } } else { this.apkFile.delete(); } this.appNameID = R.string.app_name; this.iconID = R.mipmap.ic_logo; } /** * 初始化通知 */ private void initNotification() { Intent updateCompletingIntent = new Intent(); updateCompletingIntent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); updateCompletingIntent.setClass(this.getApplication().getApplicationContext(), UpdateService.class); this.updatePendingIntent = PendingIntent.getActivity(this, this.appNameID, updateCompletingIntent, PendingIntent.FLAG_CANCEL_CURRENT); this.updateNotificationManager = (NotificationManager) this.getApplicationContext().getSystemService(Context.NOTIFICATION_SERVICE); this.builderNotification = new NotificationCompat.Builder(this.getApplicationContext()); this.builderNotification.setSmallIcon(this.iconID). setContentTitle(this.getResources().getString(this.appNameID)). setContentIntent(updatePendingIntent). setAutoCancel(true). setTicker("开始更新"). setDefaults(1). setProgress(100, 0, false). setContentText("下载进度"). build(); this.updateNotificationManager.notify(this.iconID, this.builderNotification.build()); } /** * 开始下载apk * * @param append 是否支持断点续传 */ private void downloadFile(final boolean append) { final Message message = updateHandler.obtainMessage(); int currentSize = 0; //上次下载的大小 long readSize = 0L;//已下载的总大小 long contentLength = 0;//服务器返回的数据长度 if (append) { FileInputStream fis = null; try { fis = new FileInputStream(UpdateService.this.apkFile); currentSize = fis.available();//获取上次下载的大小,断点续传可用 } catch (IOException e) { e.printStackTrace(); } finally { if (fis != null) { try { fis.close(); } catch (IOException e) { e.printStackTrace(); } } } } HttpURLConnection conn = null; InputStream is = null; FileOutputStream fos = null; try { conn = (HttpURLConnection) new URL(UpdateService.this.url).openConnection(); conn.setRequestProperty("User-Agent", "Android"); if (currentSize > 0) { conn.setRequestProperty("RANGE", "bytes=" + currentSize + "-"); } conn.setConnectTimeout(10000); conn.setReadTimeout(20000); contentLength = conn.getContentLength(); if (conn.getResponseCode() == 404) { throw new Exception("Cannot find remote file:" + UpdateService.this.url); } is = conn.getInputStream(); fos = new FileOutputStream(UpdateService.this.apkFile, append); //实时更新通知 UpdateService.this.builderNotification.setSmallIcon(iconID). setContentTitle(UpdateService.this.getResources().getString(UpdateService.this.appNameID)). setContentIntent(updatePendingIntent). setAutoCancel(true). setTicker("正在更新"). setDefaults(0). setContentText("下载进度"). build(); byte[] buffer = new byte[8*1024]; int len = 0; while ((len = is.read(buffer)) != -1) { fos.write(buffer, 0, len); readSize += len;//累加已下载的大小 int progress = (int) (readSize * 100 / contentLength); Log.d("UpdateService", (readSize * 100 / contentLength)+""); if (progress % 8 == 0) { UpdateService.this.builderNotification.setProgress(100, progress, false); UpdateService.this.updateNotificationManager.notify(iconID, UpdateService.this.builderNotification.build()); //发送广播,通知外界下载进度 sendUpdateProgress(progress); } } if (readSize == 0L) { message.what = 0; } else if (readSize == contentLength) { message.what = 1; sendUpdateProgress(100); } } catch (Exception e) { e.printStackTrace(); message.what = 0; } finally { if (conn != null) { conn.disconnect(); } IOUtils.close(is); IOUtils.close(fos); updateHandler.sendMessage(message); } } /** * 发送更新进度 * * @param progress */ private void sendUpdateProgress(int progress) { Intent intent = new Intent(ACTION_UPDATE_PROGRESS); intent.putExtra("progress", progress); sendBroadcast(intent); } /** * 下载失败通知用户重新下载 */ private void onFailNotification() { this.builderNotification.setSmallIcon(iconID). setContentTitle("更新失败,请重新下载"). setContentIntent(updatePendingIntent). setAutoCancel(true). setTicker("更新失败"). setDefaults(1). setProgress(100, 0, false). setContentText("下载进度"). build(); this.updateNotificationManager.notify(iconID, this.builderNotification.build()); } /** * 下载完毕,后通知用户点击安装 */ private void downComplete() { UpdateService.this.isUpdating = false; String cmd = "chmod 777 " + this.apkFile.getPath(); CmdUtils.execCmd(cmd); Uri uri = Uri.fromFile(this.apkFile); Intent updateCompleteIntent = new Intent("android.intent.action.VIEW"); updateCompleteIntent.addCategory("android.intent.category.DEFAULT"); updateCompleteIntent.setDataAndType(uri, "application/vnd.android.package-archive"); this.updatePendingIntent = PendingIntent.getActivity(this, this.appNameID, updateCompleteIntent, PendingIntent.FLAG_UPDATE_CURRENT); this.builderNotification.setSmallIcon(this.iconID). setContentTitle(this.getResources().getString(this.appNameID)). setContentIntent(this.updatePendingIntent). setAutoCancel(true). setTicker("更新完成"). setDefaults(1). setProgress(0, 0, false). setContentText("更新完成,点击安装"). build(); this.updateNotificationManager.notify(this.iconID, this.builderNotification.build()); } }

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

时间: 2024-10-25 00:58:20

Android下载进度监听和通知的处理详解的相关文章

Android ListView监听滑动事件的方法(详解)

ListView的主要有两种滑动事件监听方法,OnTouchListener和OnScrollListener 1.OnTouchListener OnTouchListener方法来自View中的监听事件,可以在监听三个Action事件发生时通过MotionEvent的getX()方法或getY()方法获取到当前触摸的坐标值,来对用户的滑动方向进行判断,并可在不同的Action状态中做出相应的处理 mListView.setOnTouchListener(new View.OnTouchLis

Bootstrap滚动监听(Scrollspy)插件详解_javascript技巧

滚动监听(Scrollspy)插件,即自动更新导航插件,会根据滚动条的位置自动更新对应的导航目标.其基本的实现是随着您的滚动,基于滚动条的位置向导航栏添加 .active class. 如果您想要单独引用该插件的功能,那么您需要引用 scrollspy.js.或者,正如 Bootstrap 插件概览 一章中所提到,您可以引用 bootstrap.js 或压缩版的 bootstrap.min.js. 一.用法您可以向顶部导航添加滚动监听行为: 1.通过 data 属性:向您想要监听的元素(通常是

Jsp 监听application范围属性变动详解

通过添加一个应用属性变动的监听器,我们可以监听我们应用中属性的变动情况 1.编写一个实现 ServletContextAttributeListener 的类  代码如下 复制代码 package org.Rudiment.Listener; import javax.servlet.ServletContextAttributeEvent; import javax.servlet.ServletContextAttributeListener; public class MyServletC

Android 实现监听的四种方法详解实例代码

直接上代码,大家可以参考下 (1)自身类作为事件监听器 package cn.edu.gdmec.s07150745.work5; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.Toast; public class MainActivit

js监听操作iframe 滚动事件详解

1.获取iframe页面的滚动事件  a.在包含页里面body标签添加 onscroll="fun()" [适用于chrome,不适用于IE]  b.在js里用 window.onscroll = function(){} 2.获取页面滚动条高度  代码如下 复制代码  chrome 使用 document.body.scrollTop  ie 使用 document.documentElement.scrollTop 3.框架外获取引用页信息  代码如下 复制代码  var topW

android使用OkHttp实现下载的进度监听和断点续传

1. 导入依赖包 // retrofit, 基于Okhttp,考虑到项目中经常会用到retrofit,就导入这个了. compile 'com.squareup.retrofit2:retrofit:2.1.0' // ButterKnife compile 'com.jakewharton:butterknife:7.0.1' // rxjava 本例中线程切换要用到,代替handler compile 'io.reactivex:rxjava:1.1.6' compile 'io.react

Android App内监听截图加二维码功能代码

Android截屏功能是一个常用的功能,可以方便的用来分享或者发送给好友,本文介绍了如何实现app内截屏监控功能,当发现用户在我们的app内进行了截屏操作时,进行对图片的二次操作,例如添加二维码,公司logo等一系列*. 项目地址 测试截图: 截屏原理 android系统并没有提供截屏通知相关的API,需要我们自己利用系统能提供的相关特性变通实现.Android系统有一个媒体数据库,每拍一张照片,或使用系统截屏截取一张图片,都会把这张图片的详细信息加入到这个媒体数据库,并发出内容改变通知,我们可

android截图事件监听的原理与实现

Android系统没有对用户截屏行为提供回调的api,所以我们只能走野路子来获取用户是否截屏了.一般大家都会采用如下两种方法 1.监听截屏图片所在目录变化(FileObserver) 2.监听媒体库的变化(ContentObserver) 上面两种方法均不是万能的,需要结合使用才能达到良好的效果,首先看看如何监控目录 在android中,我们可以通过FileObserver来监听目录变化,先来看看如何使用 private static final File DIRECTORY_PICTURES

android 有办法 监听 手机 有没有发出声音 或 获取当前发出声音的音量吗

问题描述 android 有办法 监听 手机 有没有发出声音 或 获取当前发出声音的音量吗 又或者说 监听 当前手机自己发出的声音的分贝,急急急, 求 解决 解决方案 个人认为,你得和硬件人员先沟通下,或者直接咨询平台公司,看支持这个功能不,就如感光sensor一样,都是需要硬件和平台支持的.