先放Google官方文档:https://developer.android.google.cn/reference/android/app/DownloadManager
简介
使用
Context.getSystemService(Context.DOWNLOAD_SERVICE)
来获取DownloadManager的实例DownloadManager可以将指定文件下载到指定位置,并处理下载出错、网络变化、系统重启等情况
需要注册一个ACTION_NOTIFICATION_CLICKED的Receiver来监听处理用户点击下载通知的事件
基础用法
首先保证应用具有
android.permission.INTERNET
权限。注册一个BroadcastReceiver,并在intent-filter标签中添加名称为
android.intent.action.DOWNLOAD_COMPLETE
和android.intent.action.DOWNLOAD_NOTIFICATION_CLICKED
的action。使用DownloadManager.Request类构建一个下载请求,并使用
DownloadManager.enqueue(request)
方法开始进行下载。这个方法会返回一个long类型的值,标记了本次下载的id。
val request = DownloadManager.Request(uri)
mId = mDownloadManager.enqueue(request)
下载完成后或用户点击通知栏的下载信息时,之前注册的Receiver会收到消息,我们在onReceive中进行处理。
开始下载之后,我们可以构建一个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) }
}
}
}