使用Android自带的DownloadManager下载文件

先放Google官方文档:https://developer.android.google.cn/reference/android/app/DownloadManager

简介

  • 使用Context.getSystemService(Context.DOWNLOAD_SERVICE)来获取DownloadManager的实例

  • DownloadManager可以将指定文件下载到指定位置,并处理下载出错、网络变化、系统重启等情况

  • 需要注册一个ACTION_NOTIFICATION_CLICKED的Receiver来监听处理用户点击下载通知的事件

基础用法

  1. 首先保证应用具有android.permission.INTERNET权限。

  2. 注册一个BroadcastReceiver,并在intent-filter标签中添加名称为android.intent.action.DOWNLOAD_COMPLETEandroid.intent.action.DOWNLOAD_NOTIFICATION_CLICKED的action。

  3. 使用DownloadManager.Request类构建一个下载请求,并使用DownloadManager.enqueue(request)方法开始进行下载。这个方法会返回一个long类型的值,标记了本次下载的id。

val request = DownloadManager.Request(uri)
mId = mDownloadManager.enqueue(request)
  1. 下载完成后或用户点击通知栏的下载信息时,之前注册的Receiver会收到消息,我们在onReceive中进行处理。

  2. 开始下载之后,我们可以构建一个DownloadManager.Query对象,通过Query.setFilterById设置第3步中获取到的id,并调用DownloadManager.query方法进行查询。query方法返回一个Cursor,和ContentProvider使用方法相同。事实上,DownloadManager的查询就是使用CotentProvider实现的。

val query = DownloadManager.Query()
query.setFilterById(mId)
val c = mDownloadManager.query(query)
c.moveToFirst()
val soFar = c.getLong(c.getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR))
val total = c.getLong(c.getColumnIndex(DownloadManager.COLUMN_TOTAL_SIZE_BYTES))
c.close()

val currentSpeed = calSpeed()
val speed = Util.byte2Human(currentSpeed)

Log.d(TAG, "已下载大小: ${Util.byte2Human(soFar)} / ${Util.byte2Human(total)} \t 下载速度: $speed/s")

完整代码

为方便阅读,所有代码都放在了一个Activity中。功能很简单,就是下载一个网络文件,并打印出下载进度,并在下载结束之后进行处理。csdn编辑器对kotlin支持不是很好啊!

package top.littlefogcat.testdownload

import android.app.Activity
import android.app.DownloadManager
import android.app.DownloadManager.ACTION_DOWNLOAD_COMPLETE
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.net.Uri
import android.os.Bundle
import android.os.SystemClock
import android.util.Log
import kotlinx.android.synthetic.main.activity_test.*
import java.util.*

class TestActivity : Activity() {
    companion object {
        const val TAG = "TestActivity"
    }

    private lateinit var mDownloadManager: DownloadManager
    private lateinit var mDownloadReceiver: DownloadReceiver
    private var mId: Long = -1
    private var mComplete = false

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_test)

        mDownloadManager = getSystemService(DOWNLOAD_SERVICE) as DownloadManager

        btnDownload.setOnClickListener {
            val url = Uri.parse(Constant.QQ_APK_URL)
            val request = DownloadManager.Request(url)
            mId = mDownloadManager.enqueue(request)

            mDownloadReceiver = DownloadReceiver()
            val filter = IntentFilter(ACTION_DOWNLOAD_COMPLETE)
            registerReceiver(mDownloadReceiver, filter)

            Thread(DownloadListener()).start()
        }
    }

    fun notifyDownloadComplete(id: Long) {
        mComplete = true
        if (mId == -1L) {
            Log.w(TAG, "notifyDownloadComplete: NO ID")
            return
        }
        val query = DownloadManager.Query()
        query.setFilterById(mId)
        val c = mDownloadManager.query(query)
        c.moveToFirst()
        val localUri = c.getString(c.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI))
        val mediaType = c.getString(c.getColumnIndex(DownloadManager.COLUMN_MEDIA_TYPE))
        Log.d(TAG, "notifyDownloadComplete: localUri = $localUri")
        Log.d(TAG, "notifyDownloadComplete: mediaType = $mediaType")
    }

    override fun onDestroy() {
        super.onDestroy()
        unregisterReceiver(mDownloadReceiver)
    }

    private inner class DownloadListener : Runnable {
        private val DEFAULT_QUEUE_SIZE = 5
        private val mSpeedQueue = LinkedList<Long>()

        override fun run() {
            while (true) {
                if (mComplete) {
                    break
                }
                val query = DownloadManager.Query()
                query.setFilterById(mId)
                val c = mDownloadManager.query(query)
                c.moveToFirst()
                val soFar = c.getLong(c.getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR))
                val total = c.getLong(c.getColumnIndex(DownloadManager.COLUMN_TOTAL_SIZE_BYTES))
                c.close()

                if (mSpeedQueue.size >= DEFAULT_QUEUE_SIZE) {
                    mSpeedQueue.poll()
                    mSpeedQueue.offer(soFar)
                } else {
                    mSpeedQueue.offer(soFar)
                }

                val currentSpeed = calSpeed()
                val speed = Util.byte2Human(currentSpeed)

                Log.d(TAG, "已下载大小: ${Util.byte2Human(soFar)} / ${Util.byte2Human(total)} \t 下载速度: $speed/s")
                SystemClock.sleep(500)
            }
        }

        private fun calSpeed(): Long {
            val size = mSpeedQueue.size
            if (size < 2) {
                return 0
            }
            return ((mSpeedQueue.last - mSpeedQueue.first) / (size - 1))
        }

    }

    private inner class DownloadReceiver : BroadcastReceiver() {
        override fun onReceive(context: Context?, intent: Intent?) {
            Log.d(TAG, "onReceive: ${intent?.action}")
            val id = intent?.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1)
            id?.let { notifyDownloadComplete(it) }
        }

    }
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值