Я внедряю IntentService
для загрузки файла PDF , он показывает уведомление пользователю на downloadStart
и продолжает обновлять прогресс во время этого процесса, служба работает нормально и прогрессобновляется правильно, проблема в том, что как только я удаляю свое приложение из «Недавних», загрузка останавливается, даже не показывая ошибку.
- Вот мой DownloadService класс:
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)
}
})
}
}
}
- и вот мой downloadFile метод, который находится в
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
, но мой файл загружался довольно долго, что не очень подходит (размер файла в 5..150 МБ). - Я использовал
ThreadPoolExcuter
/ Thread
, который обновляет уведомление с помощью runOnUiThread
, но оно также уничтожается при завершении работы приложения.Спасибо!
Редактировать : после ответа m0skit0 в методе onCreate, я создал уведомление, которое будет отображаться в течение всего процесса загрузки, показываяколичество загрузок, ожидающих обработки, пока оно показывает другое уведомление с прогрессом для каждого процесса загрузки.позвонив по номеру startForeground(ID, notification)
в onCreate, сервис будет доступен даже после закрытия приложения.
Вот мой новый 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)
}