我正在实现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)
从 downloadFile 方法返回后立即从 downloadFile 方法返回null
e.message
(在这种情况下,它返回"Unknown Error"
)之外。 catch (e : Exception)
中的处理。
有什么方法/替代方法可以在某些事件中保持文件下载和更新通知?
注意:
AsyncTask
,但是我的文件下载时间很长,这不是一个好方法(文件大小为5..150 MB)。ThreadPoolExcuter
/ Thread
来使用runOnUiThread
更新通知,但在应用程序终止时也会被杀死。
谢谢! 修改:
跟随m0skit0's Answer
在onCreate方法中,我创建了一个通知,该通知将在整个下载过程中可见,显示等待处理的下载数量,同时显示另一个通知以及每个下载过程的进度。通过在onCreate中调用startForeground(ID, notification)
,即使该应用被终止,该服务也将可用。
这是我新的 onCreate()方法:
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)
}
答案 0 :(得分:1)
要使Service
保持有效,您可以使用startForeground
API。
已启动的服务可以使用
startForeground(int, Notification)
用于将服务置于前台状态的API 认为它是用户积极了解的东西,因此 内存不足时不适合杀死。 (它还是 从理论上讲,在极端情况下可以杀死该服务 当前前台应用程序的内存压力,但是 实践,这不应该是一个问题。)