我正在实施IntentService
下载PDF文件,它在downloadStart
上向用户显示通知并在此过程中不断更新进度,服务正常工作并且进度正确更新,问题是我一删除我的来自“最近”的应用程序下载停止,甚至没有显示错误。
class DownloadService : IntentService("DownloadService") {
lateinit var downloadNotification : DownloadNotification
lateinit var book : BookData
private lateinit var fileName : String
private lateinit var fileFolder : String
private lateinit var filePath : String
lateinit var fileUrl : String
var isCancelled = false
private lateinit var handler : Handler
override fun onCreate() {
super.onCreate()
handler = Handler()
}
override fun onHandleIntent(p0: Intent?) {
book = Gson().fromJson<BookData>(p0?.getStringExtra("book"), BookData::class.java)
downloadNotification = DownloadNotification(this, book.id!!)
init(book)
}
fun getFilePath() : String {
val directory = File(fileFolder)
if (!directory.exists()) {
directory.mkdirs()
}
return filePath
}
private fun init(book : BookData) {
fileName = "${book.id}.pdf"
fileFolder = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS).toString() + File.separator + "Libranova/Books/"
filePath = fileFolder + fileName
fileUrl = book.downloadLink!!
startDownload()
}
private fun startDownload() {
downloadNotification.setTitle(book.name!!).setText("Preparing...").notificationCompat.apply {
downloadNotification.notifyManager(true)
DownloadUtils.downloadFile(this@DownloadService, object : DownloadListener {
override fun onStarted() {
handler.post {
Toast.makeText(this@DownloadService,"Download Started", Toast.LENGTH_LONG).show()
}
}
override fun onSuccess() {
downloadNotification.onFinishDownload().freeUp().setSuccess().notifyManager(true)
}
override fun onError(message: String) {
downloadNotification.onFinishDownload().freeUp().setError(message).notifyManager(true)
}
override fun onCanceled() {
downloadNotification.cancel()
}
override fun onProgress(progress: Int) {
downloadNotification.setProgress(progress).setText("$progress%").notifyManager(false)
}
})
}
}
}
object
:object DownloadUtils {
fun downloadFile(downloadService: DownloadService, downloadListener: DownloadListener) {
try {
val url = URL(downloadService.fileUrl)
val connection = url.openConnection()
connection.connect()
val lengthOfFile = connection.contentLength
val input = BufferedInputStream(url.openStream(), 8192)
val output = FileOutputStream(downloadService.getFilePath())
val data = ByteArray(1024)
var total: Long = 0
var count = input.read(data)
downloadListener.onStarted()
while (count != -1) {
if (!downloadService.isCancelled) {
total += count.toLong()
downloadListener.onProgress(((total * 100) / lengthOfFile).toInt())
output.write(data, 0, count)
count = input.read(data)
}
else break
}
output.flush()
output.close()
input.close()
if (downloadService.isCancelled) downloadListener.onCanceled() else downloadListener.onSuccess()
}
catch (e : Exception) {
downloadListener.onError(e.message ?: "Unknown Error")
}
}
fun fastFileDownload(downloadService: DownloadService) {
URL(downloadService.fileUrl).openStream().use { input ->
val folder = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS).toString() + File.separator + "Libranova/Books/"
val directory = File(folder)
if (!directory.exists()) {
directory.mkdirs()
}
FileOutputStream(File(downloadService.getFilePath())).use { output ->
input.copyTo(output)
}
}
}
}
经过长时间的互联网搜索,我发现使用Service
而不是IntentService
将解决问题,我改变了我的类结构继承Service()
而不是一切正常,除了onError(message : String)
返回null
e.message
(在这种情况下)它在"Unknown Error"
中启动进程后立即从downloadFile方法返回catch (e : Exception)
)。是否有任何方法/替代方法可以保留文件下载和更新某些事件的通知?
备注:
AsyncTask
,但我的文件下载时间很长,这不是一个好方法(fileSize在5..150 MB)。ThreadPoolExcuter
/ Thread
使用runOnUiThread
更新通知,但它也会在应用程序终止时被杀死。谢谢!编辑:在onCreate方法中跟随m0skit0's Answer,我创建了一个通知,该通知在整个下载过程中可见,显示等待处理的下载次数,同时显示每个下载过程的进度的其他通知。通过在onCreate中调用startForeground(ID, notification)
,即使应用程序被杀,该服务也将可用。
override fun onCreate() {
super.onCreate()
handler = Handler()
val notificationBuilder = NotificationCompat.Builder(this, "LibranovaDownloadService")
val notification = notificationBuilder.setOngoing(true)
.setSmallIcon(R.mipmap.ic_launcher)
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setSubText("Download Queue")
.setContentText("Waiting For Download : 1 Book")
.setCategory(NotificationCompat.CATEGORY_SERVICE)
.build()
startForeground(123, notification)
}为了让Service
保持活力,您可以使用startForeground
API。
启动的服务可以使用
startForeground(int, Notification)
API将服务置于前台状态,系统认为该服务是用户主动了解的内容,因此在内存不足时不会成为查杀的候选者。 (从理论上讲,服务在当前前台应用程序的极端内存压力下被杀死仍然是可能的,但实际上这不应该是一个问题。)