内容简介:在Android开发中,许多时候都会用到大文件下载功能,例如app更新、缓存视频文件等。之前我们开发团队里布置了一次作业,写的是关于利用RandomAcceseeFile和service来实现一个下载器,需要考虑到例如异步、后台下载、暴露回调接口、自动安装等策略,对于初级Android工程师来说,项目比较赶的时候可能就会影响效率。那么,有没有一个库能够简单粗暴地完成这些任务呢?当然,那就是Google官方的DownloadManager
在Android开发中,许多时候都会用到大文件下载功能,例如app更新、缓存视频文件等。之前我们开发团队里布置了一次作业,写的是关于利用RandomAcceseeFile和service来实现一个下载器,需要考虑到例如异步、后台下载、暴露回调接口、自动安装等策略,对于初级Android工程师来说,项目比较赶的时候可能就会影响效率。那么,有没有一个库能够简单粗暴地完成这些任务呢?
当然,那就是Google官方的DownloadManager
介绍
我们看看官方对于两个主要内部类的介绍:
Nested classes | description |
---|---|
DownloadManager.Query | This class may be used to filter download manager queries. |
DownloadManager.Request | This class contains all the information necessary to request a new download. |
顾名思义DownloadManager.Query主要用于查询下载的信息,DownloadManager.Request主要用于发起一个下载请求(其中可以添加下载的配置,例如Header等信息)
基本使用
1.设置权限
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> 复制代码
2. 构造Request对象
val url = "http://hongyan.cqupt.edu.cn/app/com.mredrock.cyxbs.apk?version=44.0"//下载地址 val uri: Uri = Uri.parse(url)//转变为Uri val request:DownloadManager.Request = DownloadManager.Request(uri)//构造request实例 复制代码
3. 配置Request的信息
request.setTitle("下载任务") request.setDescription("下载掌上重邮app中...") request.allowScanningByMediaScanner() request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI) request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED) request.setDestinationInExternalFilesDir(this, Environment.DIRECTORY_DOWNLOADS, "cyxbs") //... 复制代码
部分配置:
- addRequestHeader(String header,String value) 添加请求头
- allowScanningByMediaScanner() 表示允许MediaScanner扫描到这个文件,默认不允许
- setAllowedNetworkTypes(int flags) 设置下载时的网络条件,默认任何网络都可以下载,可选配置:NETWORK_BLUETOOTH、NETWORK_MOBILE、NETWORK_WIFI。
- setAllowedOverRoaming(Boolean allowed) 漫游状态下是否可以下载
- setNotificationVisibility(int visibility) 设置下载完成或下载时是否发布通知
- setTitle(CharSequence):设置Notification的title
- setDescription(CharSequence):设置Notification的message
- setDestinationInExternalFilesDir 设置路径为应用程序外部文件目录
- setDestinationInExternalPublicDir 设置路径为外部存储目录
- setDestinationUri 设置路径
- setMimeType(String mimeType) 设置MIME内容类型
4.获取DownloadManager实例
val downloadManager = getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager 复制代码
5.加入下载队列
val downloadId = downloadManager.enqueue(request) 复制代码
6.其他操作
//remove方法可以用来取消一个准备进行的下载,中止一个正在进行的下载,或者删除一个已经完成的下载。 downloadManager.remove(downloadId)//移除请求队列,取消下载 复制代码
监听DownloadManager的广播
DownloadManager会在完成时发送一条 ACTION_DOWNLOAD_COMPLETE 的广播,这时我们只需要创建一个BroadCastReceiver就能接收到下载完成的信息
创建BroadCastReceiver的子类来接收广播
class DownLoadFinishReceiver : BroadcastReceiver(){ override fun onReceive(context: Context?, intent: Intent?) { intent?.let { val action = intent.action if (action == DownloadManager.ACTION_DOWNLOAD_COMPLETE) { //下载完成操作 } else if (action == DownloadManager.ACTION_NOTIFICATION_CLICKED) { //点击Notification的操作 例如暂停操作 } } } } 复制代码
动态注册广播接收器
val downLoadFinishReceiver = DownLoadFinishReceiver() val intentFilter = IntentFilter() intentFilter.addAction(DownloadManager.ACTION_DOWNLOAD_COMPLETE) intentFilter.addAction(DownloadManager.ACTION_NOTIFICATION_CLICKED) registerReceiver(downLoadFinishReceiver, intentFilter) 复制代码
别忘了在onDestroy里解除
override fun onDestroy() { super.onDestroy() unregisterReceiver(downLoadFinishReceiver) } 复制代码
Query的使用
query主要用于查询下载的信息,DownloadManager类中内置了很多的字段可以供Query来查询,例如状态、文件下载路径等。
Public method | description |
---|---|
setFilterById(long... ids) | 仅包括给定id的下载文件 |
setFilterByStatus(int flags) | 仅包含状态与给定状态匹配的下载文件 |
结合Cursor,我们可以查询到DownloadManager里有的信息,包括下载文件的Uri,下载状态等。具体字段可以进入DownloadManager源码中查看。
查询下载状态
private fun queryStatus(){ val query = DownloadManager.Query().setFilterById(downloadId) val cursor = manager.query(query) if(cursor!=null){ if(cursor.moveToFirst()){ val status = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS)) when(status){ DownloadManager.STATUS_RUNNING->{ //下载中 } DownloadManager.STATUS_FAILED->{ //下载失败 } DownloadManager.STATUS_PAUSED->{ //下载暂停 } DownloadManager.STATUS_PENDING->{ //下载延迟 } DownloadManager.STATUS_SUCCESSFUL->{ //下载成功 } } } } cursor.close() } 复制代码
查询下载的文件的部分信息
这里DownloadManager封装好了两种查询的方法,其内部都是使用Query+Cursor的组合实现的。
manager.getUriForDownloadedFile(downloadId) //下载完成的文件的Uri,你可以拿到这个uri去操作他,例如apk安装 manager.getMimeTypeForDownloadedFile(downloadId) //下载完成的文件的media type 复制代码
你也可以查询其他信息
DownloadManager.COLUMN_ID//下载id DownloadManager.COLUMN_TITLE//下载文件的题目 DownloadManager.COLUMN_LOCAL_URI//下载文件的uri DownloadManager.COLUMN_STATUS//下载文件的状态 DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR//目前文件的大小 DownloadManager.COLUMN_TOTAL_SIZE_BYTES//文件的总大小 复制代码
多说一句,若想回调进度,你可以根据上面的 文件目前大小 / 文件总大小 来得到,刷新进度可以使用Hanlder+Timer(仅供参考)
自动安装Apk
首先列出兼容7.0的方法,因为7.0时引入了"StrictMode Api"政策,禁止向你的应用外公开uri,如果Intent跳转到应用外,则会出现FileUriExposedException,所以说我们要添加一个flag去获得临时授权
private fun installApk(downloadId: Long) { val uri = manager.getUriForDownloadedFile(downloadId) val intent = Intent(Intent.ACTION_VIEW) if (uri != null) { intent.setDataAndType(uri,"application/vnd.android.package-archive") if ((Build.VERSION.SDK_INT >= 24)) {//版本是否在7.0以上 intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) //对目标apk的uri临时授权 使得有权限打开该Uri指向的Apk } intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) if (intent.resolveActivity(packageManager) != null) { startActivity(intent) } else { Log.e("DownloadManager","自动安装失败") } }else{ Log.e("DownloadManager","下载失败") } } 复制代码
其次,8.0时禁止安装未知来源的apk,直接安装会闪退,所以说我们加入这条权限,就能跳转到一个让用户手动允许安装未知来源的界面。
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/> 复制代码
自动更新
(流程图练手)
后话
因为Request要设置的参数比较多,适合Builder模式,所以说大家可以写一个RequsetBuilder来配置Request对象,比较美观,简单修改如下。
class RequestBuilder { private lateinit var request:DownloadManager.Request private lateinit var uri: Uri private lateinit var context:Context fun with(context: Context):RequestBuilder{ this.context = context return this } fun downloadUrl(url:String):RequestBuilder{ this.uri = Uri.parse(url) this.request = DownloadManager.Request(uri) return this } fun setTitle(title: String):RequestBuilder{ request.setTitle(title) return this } fun setDescription(description: String):RequestBuilder{ request.setDescription(description) return this } fun allowScanningByMediaScanner():RequestBuilder{ request.allowScanningByMediaScanner() return this } fun setNetworkType(networkType:Int):RequestBuilder{ request.setAllowedNetworkTypes(networkType) return this } fun setNotificationVisibility(visibility:Int):RequestBuilder{ request.setNotificationVisibility(visibility) return this } fun setDefaultDestination(subPath:String):RequestBuilder{ request.setDestinationInExternalFilesDir(context, Environment.DIRECTORY_DOWNLOADS, subPath) return this } fun build():DownloadManager.Request{ return request } } 复制代码
此外,记得缓存downloadId,否则退出界面之后id就丢失了。
以上所述就是小编给大家介绍的《接锅太急?DownloadManager助你一臂之力》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。