android中DownloadManager实现版本更新,监听下载进度实例

DownloadManager简介

DownloadManager是Android 2.3(API level 9)用系统服务(Service)的方式提供了DownloadManager来处理长时间的下载操作。它包含两个静态内部类DownloadManager.Query(用来查询下载信息)和DownloadManager.Request(用来请求一个下载)。

DownloadManager主要提供了下面几个方法:

public long enqueue(Request request)把任务加入下载队列并返回downloadId,以便后面用于查询下载信息。若网络不满足条件、Sdcard挂载中、超过最大并发数等异常会等待下载,正常则直接下载。

public int remove(long… ids)删除下载,若取消下载,会同时删除下载文件和记录。

public Cursor query(Query query)查询下载信息,包括下载文件总大小,已经下载的大小以及下载状态等。

ContentObserver简介

public void ContentObserver(Handler handler) 所有ContentObserver的派生类都需要调用该构造方法,参数:handler Handler对象用于在主线程中修改UI。

public void onChange(boolean selfChange)当观察到的Uri中内容发生变化时,就会回调该方法。所有ContentObserver的派生类都需要重载该方法去处理逻辑。

观察特定Uri的步骤如下:

1、创建我们特定的ContentObserver派生类,必须重载父类构造方法,必须重载onChange()方法去处理回调后的功能实现。

2、为指定的Uri注册一个ContentObserver派生类实例,当给定的Uri发生改变时,回调该实例对象去处理,调用registerContentObserver()方法去注册内容观察者。

3、由于ContentObserver的生命周期不同步于Activity和Service等。因此,在不需要时,需要手动的调用unregisterContentObserver()注销内容观察者。

效果图:

一:执行下载

下载配置

downloadManager = (DownloadManager) getSystemService(DOWNLOAD_SERVICE);
downloadObserver = new DownloadChangeObserver();
//在执行下载前注册内容监听者
registerContentObserver();
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url));
/**设置用于下载时的网络状态*/
request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI | DownloadManager.Request.NETWORK_MOBILE);
/**设置通知栏是否可见*/
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_HIDDEN);
/**设置漫游状态下是否可以下载*/
request.setAllowedOverRoaming(false);
/**如果我们希望下载的文件可以被系统的Downloads应用扫描到并管理,
我们需要调用Request对象的setVisibleInDownloadsUi方法,传递参数true.*/
request.setVisibleInDownloadsUi(true);
/**设置文件保存路径*/
request.setDestinationInExternalFilesDir(getApplicationContext(), "phoenix", "phoenix.apk");
/**将下载请求放入队列, return下载任务的ID*/
downloadId = downloadManager.enqueue(request);
//执行下载任务时注册广播监听下载成功状态
registerBroadcast();

添加权限

<!--网络通信权限-->
<uses-permission android:name="android.permission.INTERNET"/>
<!--SD卡写入数据权限-->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<!--SD卡创建与删除权限-->
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
<!--VISIBILITY_HIDDEN表示不显示任何通知栏提示的权限-->
<uses-permission android:name="android.permission.DOWNLOAD_WITHOUT_NOTIFICATION"/>
<!--DownloadManager-->
<uses-permission android:name="android.permission.ACCESS_DOWNLOAD_MANAGER"/>
在清单文件中注册Service
<!--版本更新服务-->
<service android:name="com.github.phoenix.service.DownloadService"></service>

二:监听下载进度

注册ContentObserver

三个参数分别是所要监听的Uri、false表示精确匹配此Uri,true表示可以匹配其派生的Uri、ContentObserver的派生类实例。

/**
* 注册ContentObserver
*/
private void registerContentObserver() {
 /** observer download change **/
 if (downloadObserver != null) {
   getContentResolver().registerContentObserver(Uri.parse("content://downloads/my_downloads"), true, downloadObserver);
 }
}

查询已下载数据大小

为了提高性能,在这里开启定时任务,每2秒去查询数据大小并发送到handle中更新UI。

/**
* 监听下载进度
*/
private class DownloadChangeObserver extends ContentObserver {

 public DownloadChangeObserver() {
   super(downLoadHandler);
   scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
 }

 /**
  * 当所监听的Uri发生改变时,就会回调此方法
  *
  * @param selfChange 此值意义不大, 一般情况下该回调值false
  */
 @Override
 public void onChange(boolean selfChange) {
   scheduledExecutorService.scheduleAtFixedRate(progressRunnable, 0, 2, TimeUnit.SECONDS);
 }
}
/**
* 通过query查询下载状态,包括已下载数据大小,总大小,下载状态
*
* @param downloadId
* @return
*/
private int[] getBytesAndStatus(long downloadId) {
 int[] bytesAndStatus = new int[]{
     -1, -1, 0
 };
 DownloadManager.Query query = new DownloadManager.Query().setFilterById(downloadId);
 Cursor cursor = null;
 try {
   cursor = downloadManager.query(query);
   if (cursor != null && cursor.moveToFirst()) {
     //已经下载文件大小
     bytesAndStatus[0] = cursor.getInt(cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR));
     //下载文件的总大小
     bytesAndStatus[1] = cursor.getInt(cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_TOTAL_SIZE_BYTES));
     //下载状态
     bytesAndStatus[2] = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS));
   }
 } finally {
   if (cursor != null) {
     cursor.close();
   }
 }
 return bytesAndStatus;
}

Activity与Service通信

既然我们要在Activity中实时更新下载进度,那么就需要Activity绑定Service建立通信。

在Service中提供一个接口实时回调进度值。用isBindService来标识Activity是否绑定过Service,在调用bindService(ServiceConnection conn)方法时,如果绑定成功会返回true,否则返回false,只有返回true时才可以进行解绑,否则报错。

private ServiceConnection conn = new ServiceConnection() {

 @Override
 public void onServiceConnected(ComponentName name, IBinder service) {
   DownloadService.DownloadBinder binder = (DownloadService.DownloadBinder) service;
   DownloadService downloadService = binder.getService();

   //接口回调,下载进度
   downloadService.setOnProgressListener(new DownloadService.OnProgressListener() {
     @Override
     public void onProgress(float fraction) {
       LogUtil.i(TAG, "下载进度:" + fraction);
       bnp.setProgress((int)(fraction * 100));

       //判断是否真的下载完成进行安装了,以及是否注册绑定过服务
       if (fraction == DownloadService.UNBIND_SERVICE && isBindService) {
         unbindService(conn);
         isBindService = false;
         MToast.shortToast("下载完成!");
       }
     }
   });
 }

 @Override
 public void onServiceDisconnected(ComponentName name) {

 }
};

三:广播监听下载成功

下载完成,自动安装,记录APK存储路径

在下载成功后把APK存储路径保存到SP中,同时关闭定时器,开启apk安装界面。

/**
* 安装APK
* @param context
* @param apkPath 安装包的路径
*/
public static void installApk(Context context, Uri apkPath) {
 Intent intent = new Intent();
 intent.setAction(Intent.ACTION_VIEW);
 //此处因为上下文是Context,所以要加此Flag,不然会报错
 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
 intent.setDataAndType(apkPath, "application/vnd.android.package-archive");
 context.startActivity(intent);
}

四:善后处理

1、关闭定时器,线程

当收到下载完成的广播时立即停掉定时器,取消线程。

2、解绑Service,注销广播,注销ContentObserver

当Service解绑的时候,要把监听下载完成的广播和监听下载进度的ContentObserver注销。

3、删除APK

当应用安装成功后,再次启动就执行删除Apk操作。

/**
* 删除上次更新存储在本地的apk
*/
private void removeOldApk() {
 //获取老APK的存储路径
 File fileName = new File(SPUtil.getString(Constant.SP_DOWNLOAD_PATH, ""));
 LogUtil.i(TAG, "老APK的存储路径 =" + SPUtil.getString(Constant.SP_DOWNLOAD_PATH, ""));

 if (fileName != null && fileName.exists() && fileName.isFile()) {
   fileName.delete();
   LogUtil.i(TAG, "存储器内存在老APK,进行删除操作");
 }
}

五:具体应用

首先上传当前应用版本号给服务器,让服务器检查是否可以进行版本更新;如果可以进行版本更新,则绑定Service,开始下载APK,下载完成直接弹出安装界面,同时记录APK存储路径;待下次启动时,检查删除APK。

源码:DownloadManager_jb51.rar

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

时间: 2017-03-10

Android 检查更新、下载、安装功能的实现

android检查更新.下载.安装 前言: 由于友盟更新即将下线,我们就修改了更新逻辑,自己检查更新.下载.安装,但是检查更新还是要依赖于友盟中的在线参数: 1.MainActivity.Java: public class MainActivity extends BaseActivity{ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setCon

Android SDK Manager更新、下载速度慢问题解决办法

Android SDK Manager更新.下载速度慢问题解决办法 解决Android SDK Manager更新.下载速度慢 打开目录 C:\Windows\System32\drivers\etc,在目录下有hosts文件 打开文件添加如下文本 203.208.46.146 www.google.com 74.125.113.121 developer.android.com 203.208.46.146 dl.google.com 203.208.46.146 dl-ssl.google.

Android中使用AsyncTask实现文件下载以及进度更新提示

Android提供了一个工具类:AsyncTask,它使创建需要与用户界面交互的长时间运行的任务变得更简单.相对Handler来说AsyncTask更轻量级一些,适用于简单的异步处理,不需要借助线程和Handter即可实现.AsyncTask是抽象类.AsyncTask定义了三种泛型类型Params,Progress和Result: Params启动任务执行的输入参数,比如,HTTP请求的URL. Progress后台任务执行的百分比. Result后台执行任务最终返回的结果,比如String.

Android Studio下载更新Android SDK网络异常或无法下载

Android Studio下载更新Android SDK网络异常或无法下载 今天重新安装了下Android Studio,在安装SDK时老是提示网络异常,于是上网查了下, 解决方法如下:HTTP Proxy中Host name设置为mirrors.neusoft.edu.cn 再勾选 这样设置就好了,试了下下载速度很快,感谢好心人提供的方法 感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!

Android中使用AsyncTask实现下载文件动态更新进度条功能

1. 泛型 AysncTask<Params, Progress, Result> Params:启动任务时传入的参数,通过调用asyncTask.execute(param)方法传入. Progress:后台任务执行的进度,若不用显示进度条,则不需要指定. Result:后台任务结束时返回的结果. 2. 重要方法 doInBackground(Params... params):必须重写的方法,后台任务就在这里执行,会开启一个新的线程.params为启动任务时传入的参数,参数个数不定. on

Android编程实现下载时主界面与详细界面一致更新的方法

本文实例讲述了Android编程实现下载时主界面与详细界面一致更新的方法.分享给大家供大家参考,具体如下: 1.创建监听管理类 public class ObserverManager { private List<Observer> observers = new ArrayList<ObserverManager.Observer>(); public interface Observer { public void update(); public void updateSt

Android实现检查并下载APK更新、安装APK及获取网络信息的方法

本文所述实例为一个天气预报中的android代码,主要包括了下载和安装APK.检查Apk更新.显示'已经是最新'或者'无法获取版本信息'对话框.获取当前客户端版本信息.显示版本更新通知对话框.显示下载对话框.判断是否挂载了SD卡.显示文件大小格式:2个小数点显示等.具体实现代码如下: import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileOutputStream; import java.io.I

android实现通知栏下载更新app示例

1.设计思路,使用VersionCode定义为版本升级参数.android为我们定义版本提供了2个属性: 复制代码 代码如下: <manifest package="com.cnblogs.tianxia.subway"android:versionCode="1" <!--Integer类型,系统不显示给用户-->android:versionName="1.0"<!--String类型,系统显示用户-->>

Android编程实现应用自动更新、下载、安装的方法

本文实例讲述了Android编程实现应用自动更新.下载.安装的方法.分享给大家供大家参考,具体如下: 我们看到很多Android应用都具有自动更新功能,用户一键就可以完成软件的升级更新.得益于Android系统的软件包管理和安装机制,这一功能实现起来相当简单,下面我们就来实践一下. 1. 准备知识 在AndroidManifest.xml里定义了每个Android apk的版本标识: <manifest xmlns:android="http://schemas.android.com/a

Android应用程序更新并下载实例

整理文档,搜刮出一个Android应用程序更新并下载实例的代码,稍微整理精简一下做下分享. 创建一个新类,名为UpdateManager,代码如下: import java.io.BufferedReader; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader;

Android程序版本更新之通知栏更新下载安装

Android应用检查版本更新后,在通知栏下载,更新下载进度,下载完成自动安装,效果图如下: •检查当前版本号 AndroidManifest文件中的versionCode用来标识版本,在服务器放一个新版本的apk,versioncode大于当前版本,下面代码用来获取versioncode的值 PackageInfo packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), 0); int

android 版本检测 Android程序的版本检测与更新实现介绍

做个网站的安卓客户端,用户安装到自己手机上,如果我出了新版本怎么办呢?要有版本更新功能. 本来版本检测最好可以自动进行.但如果每次开启程序,都要先检测一轮,是一种浪费,毕竟版本更新是小概率的事情.或许可以程序开启的时候,判断一下时间,单日就检测,双日就不检测,或者随机什么的,降低一下检测的频率? 我采取的做法是将检测功能做到了菜单上,用户有需要,就手动打开自己检测一下.反正我们这个是网站客户端,有版本更新,在网站上发个通告就行了. 版本检测与更新有以下几个关键步骤: 1.检测有无新版本 2.下载

Android程序自动更新功能模块的实现方法【附完整demo源码下载】

本文实例讲述了Android程序自动更新功能模块的实现方法.分享给大家供大家参考,具体如下: 在程序启动的时候检测服务器上有没有对应版本更新,如果有更新,提示用户是否更新. 在程序启动的时候首先调用更新模块检测服务器上存放的版本号跟当前程序的版本号如果大于当前版本号,弹出更新对话框,如果用户选择更新,则显示当前更新状态,然后替换当前程序. 程序调用版本更新检测: private UpdateManager updateMan; private ProgressDialog updateProgr

Android程序静默安装安装后重新启动APP的方法

 一:需求简介 之前boss提出一个需求,运行在广告机上的app,需要完成自动升级的功能,广告机是非触摸屏的,不能通过手动点击,所以app必须做到自动下载,自动安装升级,并且安装完成后,app还要继续运行,最好不借助其它app来实现以上功能.  二:实现思路 实现这个功能第一个想到的方法就是静默安装,由于广告机已经root,静默安装比较顺利,安装app的主要代码如下: /* @pararm apkPath 等待安装的app全路径,如:/sdcard/app/app.apk **/ private

windows server 2008 阻止恶意插件程序下载安装到系统中

当我们使用Windows Server 2008系统自带的IE浏览器访问Internet网络中的站点内容时,经常会看到有一些恶意插件程序偷偷在系统后台进行安装操作,一旦安装完毕后,我们往往很难将它们从系统中清除干净,并且它们的存在直接影响着Windows Server 2008系统的工作状态以及运行安全.为了不让恶意插件程序偷袭Windows Server 2008系统,我们可以通过下面的设置操作,来阻止任何来自Internet网络中的下载文件安装保存到本地系统中: 首先以系统管理员身份进入Wi

VS2015 Update2 构建 Android 程序问题汇总

自VS2015起, Visual Studio开始逐渐内置支持跨平台开发, 并且Visual Studio团队还额外发布了一个编译工具集Clang with Microsoft CodeGen, 方便开发人员进行跨平台代码的开发, 该工具集在VS 2015 Update 2时采用的 Clang 版本号是3.7. 与此同时VS的移动开发能力也不再局限于Windows Phone, 而是支持了包括Android, iOS在内的主流平台的应用开发. 和其它新特性首次被引入一样, 虽然历经了两次Upda