安卓笔记 - 2020-03-20 - 封装下载器

下载器封装,便于开发,使用downloadManager。可以监听下载进度,监听方法里使用了协程,也可以使用线程进行监听,同时使用contentProvider来获取全局上下文,所以在使用中无需传递上下文。

此文仅用于本人记录开发经验所用。

```

/**

*@Company NSNTC

*@author Chord.p

*@time 2020/3/20 9:44 AM

*speak softly love

*

* 下载器,暂时无法管理多下载任务状态

*/

class DownloadHelper {

//下载器

    private var downloadManager : DownloadManager = DownloadProvider.mContext.getSystemService(Context.DOWNLOAD_SERVICE)as DownloadManager

//下载时相关配置

    private var options = DownloadOptions()

//下载开始监听器,回调参数为下载id,可通过该id对该下载任务进行管理

    var preparListener : DownloadBaseListener? =null

    //下载中监听器,回调参数为下载进度,范围在0~100

    var downloadingListener : DownloadBaseListener? =null

    //下载失败监听器

    var downloadFailListener : DownloadNoteListener? =null

    //下载延迟监听器

    var downloadPenddingListener : DownloadNoteListener? =null

    //下载暂停监听器

    var downloadPauseListener : DownloadNoteListener? =null

    //下载成功监听器,回调参数为本地存储路径

    var downloadSuccessListener : DownloadBaseListener? =null

    //下载周期监听器

    var downloadListener : DownloadListener? =null

    //下载id

    var id =0L

    //下载地址

    var path =""

    companion object {

val instance : DownloadHelperby lazy(::DownloadHelper)

fun apkDownload(url : String,name : String,deleteIfExists : Boolean =true) {

instance.downloadApk(url, name, deleteIfExists)

}

fun downloadFile(url : String,name : String,deleteIfExists : Boolean =true) {

instance.download(url, name, deleteIfExists)

}

/**

* 请使用DownloadOptions下的常量进行设定

*/

        fun setNetType(type : String) {

instance.options.netType = type

}

fun setDownloadPath(path : String) {

instance.options.downloadPath = File(path)

}

fun setDownloadPath(path : File) {

instance.options.downloadPath = path

}

/**

* 请使用DownloadManager.Request 下的常量进行设定

*/

        fun setShowNotify(showType : Int) {

instance.options.showNotify = showType

}

fun setDownloadListener(listener : DownloadListener) {

instance.downloadListener = listener

}

fun setPrepardListener(listener: DownloadBaseListener) {

instance.preparListener = listener

}

fun setNotifyTitle(title: String) {

instance.options.title = title

}

fun setNotifyDesc(desc : String) {

instance.options.desc = desc

}

}

fun downloadApk(url : String,name : String,deleteIfExists : Boolean =true) {

var request = DownloadManager.Request(Uri.parse(url))

request.setAllowedOverRoaming(false)

when(options.netType) {

DOWNLOAD_ONLY_PHONE -> request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_MOBILE)

DOWNLOAD_ONLY_WIFI -> request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI)

DOWNLOAD_NO_CARE -> request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_MOBILE or DownloadManager.Request.NETWORK_WIFI)

}

//设置是否显示通知栏

        request.setNotificationVisibility(options.showNotify)

//设置通知栏标题

        request.setTitle(options.title)

//设置通知栏简介

        request.setDescription(options.desc)

request.setVisibleInDownloadsUi(true)

//指定下载的文件类型为APK

        request.setMimeType("application/vnd.android.package-archive")

var file = File(options.downloadPath,name)

//若已存在该文件,则删除

        if (file.exists()) {

if (deleteIfExists) {

file.delete()

}else{

Log.e("download","file is exists")

return

            }

}

request.setDestinationUri(Uri.fromFile(file))

path = file.absolutePath

        id =downloadManager.enqueue(request)

preparListener?.onNotice?.invoke(id)

downloadListener?.onPrepare(id)

//注册广播,接收下载任务广播

        DownloadProvider.mContext.registerReceiver(receiver,IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE))

downloadProgress(id)

}

fun download(url : String,name : String,deleteIfExists : Boolean =true) {

var request = DownloadManager.Request(Uri.parse(url))

request.setAllowedOverRoaming(false)

when(options.netType) {

DOWNLOAD_ONLY_PHONE -> request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_MOBILE)

DOWNLOAD_ONLY_WIFI -> request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI)

DOWNLOAD_NO_CARE -> request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_MOBILE or DownloadManager.Request.NETWORK_WIFI)

}

//设置是否显示通知栏

        request.setNotificationVisibility(options.showNotify)

//设置通知栏标题

        request.setTitle(options.title)

//设置通知栏简介

        request.setDescription(options.desc)

request.setVisibleInDownloadsUi(true)

var file = File(options.downloadPath,name)

//若已存在该文件,则删除

        if (file.exists()) {

if (deleteIfExists) {

file.delete()

}else{

Log.e("download","file is exists")

return

            }

}

request.setDestinationUri(Uri.fromFile(file))

path = file.absolutePath

        id =downloadManager.enqueue(request)

preparListener?.onNotice?.invoke(id)

downloadListener?.onPrepare(id)

//注册广播,接收下载任务广播

        DownloadProvider.mContext.registerReceiver(receiver,IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE))

downloadProgress(id)

}

//开协程用于监听下载进度

    fun downloadProgress(id : Long) {

GlobalScope.launch {

            var breakFlag =true

            var query = DownloadManager.Query()

do {

query.setFilterById(id)

var cursor =downloadManager.query(query)

if (cursor.moveToFirst()) {

var bytes_downloaded = cursor.getInt(cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR))

var bytes_total = cursor.getInt(cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_TOTAL_SIZE_BYTES))

var dl_progress = (bytes_downloaded *100 / bytes_total)

withContext(Dispatchers.Main){

                        downloadingListener?.onNotice?.invoke(dl_progress)

downloadListener?.onDownloading(dl_progress)

}

                when {

dl_progress ==100 -> breakFlag =false

                    cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS)) == DownloadManager.STATUS_SUCCESSFUL -> breakFlag =false

                    cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS)) == DownloadManager.STATUS_FAILED -> breakFlag =false

                }

}

cursor.close()

delay(200)

}while (breakFlag)

}

    }

//广播接受者,接收下载任务的广播

    private var receiver =object : BroadcastReceiver() {

override fun onReceive(context: Context?, intent: Intent?) {

var query = DownloadManager.Query()

query.setFilterById(id)

var cursor =downloadManager.query(query)

if (cursor.moveToFirst()) {

when(cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS))) {

//正在下载

                    DownloadManager.STATUS_RUNNING -> {

}

//下载失败

                    DownloadManager.STATUS_FAILED -> {

downloadFailListener?.onNotice?.invoke()

downloadListener?.onFail()

cursor.close()

DownloadProvider.mContext.unregisterReceiver(this)

}

//下载暂停

                    DownloadManager.STATUS_PAUSED -> {

downloadPauseListener?.onNotice?.invoke()

downloadListener?.onPaused()

}

//下载成功

                    DownloadManager.STATUS_SUCCESSFUL -> {

downloadSuccessListener?.onNotice?.invoke(path)

downloadListener?.onSuccess(path)

cursor.close()

DownloadProvider.mContext.unregisterReceiver(this)

}

//下载延迟

                    DownloadManager.STATUS_PENDING -> {

downloadPenddingListener?.onNotice?.invoke()

downloadListener?.onPending()

}

}

}

}

}


//立即安装app

fun installApk(path : String) {

DownloadProvider.mContext.startActivity(Intent().apply {

        this.action = Intent.ACTION_VIEW

        this.flags = Intent.FLAG_ACTIVITY_NEW_TASK

        this.setDataAndType(Uri.parse(path),"application/vnd.android.package-archive")

})

}

fun installApk(path : Uri) {

DownloadProvider.mContext.startActivity(Intent().apply {

        this.action = Intent.ACTION_VIEW

        this.flags = Intent.FLAG_ACTIVITY_NEW_TASK

        this.setDataAndType(path,"application/vnd.android.package-archive")

})

}

class DownloadBaseListener (onNotice : (value :T) -> Unit) {var onNotice = onNotice }

class DownloadNoteListener(onNotice : () -> Unit) {var onNotice = onNotice }

interface DownloadListener {

open fun onPrepare(id: Long) {}

open fun onDownloading(progress : Int) {}

open fun onFail() {}

open fun onPaused() {}

open fun onSuccess(path : String) {}

open fun onPending() {}

}

//用于存储下载时所需的配置

    class DownloadOptions(showNotify : Int = DownloadManager.Request.VISIBILITY_HIDDEN,title : String ="",desc : String ="") {

//是否展示通知栏

        var showNotify = showNotify

//通知栏标题

        var title = title

//通知栏简介

        var desc = desc

//下载环境

        var netType =DOWNLOAD_NO_CARE

        //下载存储地址

        var downloadPath = DownloadProvider.mContext.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS)

companion object {

//网络环境

            const val DOWNLOAD_ONLY_PHONE ="phone"

            const val DOWNLOAD_ONLY_WIFI ="wifi"

            const val DOWNLOAD_NO_CARE ="noCare"

        }

}

//用于获取全局上下文

    class DownloadProvider : ContentProvider() {

companion object {

lateinit var mContext : Context

}

override fun insert(uri: Uri, values: ContentValues?): Uri? {

return null

        }

override fun query(uri: Uri, projection: Array?, selection: String?, selectionArgs: Array?, sortOrder: String?): Cursor? {

return null

        }

override fun onCreate(): Boolean {

mContext =context!!

return false

        }

override fun update(uri: Uri, values: ContentValues?, selection: String?, selectionArgs: Array?): Int {

return 0

        }

override fun delete(uri: Uri, selection: String?, selectionArgs: Array?): Int {

return 0

        }

override fun getType(uri: Uri): String? {

return null

        }

}

}

```

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,490评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,581评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,830评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,957评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,974评论 6 393
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,754评论 1 307
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,464评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,357评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,847评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,995评论 3 338
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,137评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,819评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,482评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,023评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,149评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,409评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,086评论 2 355

推荐阅读更多精彩内容