title: IntentService/Service - Keep running even if the application is terminated - Android
body: <p>I'm implementing an <code>IntentService</code> to download a <strong>PDF</strong> file, it shows a notification to the user on <code>downloadStart</code> and keep updating progress during this process, the service is working fine and the progress is updated correctly, the problem is as soon as i remove my app from "Recents" the download stops without even showing an error.</p>
  
  <ul>
  <li>Here's my <strong>DownloadService</strong> class :</li>
  </ul>
  
  <p><div class="snippet" data-lang="js" data-hide="false" data-console="true" data-babel="false">
  <div class="snippet-code">
  <pre class="snippet-code-html lang-html prettyprint-override"><code>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&lt;BookData&gt;(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)
              }
  
          })
      }
  
  }
  }</code></pre>
  </div>
  </div>
  </p>
  
  <ul>
  <li>and here's my <strong>downloadFile</strong> method which is located in an <code>object</code>:</li>
  </ul>
  
  <p><div class="snippet" data-lang="js" data-hide="false" data-console="true" data-babel="false">
  <div class="snippet-code">
  <pre class="snippet-code-html lang-html prettyprint-override"><code>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 -&gt;
              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 -&gt;
                  input.copyTo(output)
              }
          }
      }
  }</code></pre>
  </div>
  </div>
  </p>
  
  <p>After a long searching on the internet, i have found that using a <code>Service</code> instead of <code>IntentService</code> will solve the problem, i have changed my class structure to inherit from <code>Service()</code> instead, everything worked fine except for the <code>onError(message : String)</code> returning a <code>null</code> <code>e.message</code> (in this case it returns <code>"Unknown Error"</code>) from the <strong>downloadFile</strong> method immediately after starting the process in <code>catch (e : Exception)</code>.
  Is there any way/alternative to keep the file downloading and updating the notification on certain events? </p>
  
  <p>Notes : </p>
  
  <ul>
  <li>i have used <code>AsyncTask</code> before but my file take pretty long to download which is not a good approach (fileSize in 5..150 MB).</li>
  <li>i have used <code>ThreadPoolExcuter</code>/<code>Thread</code> that updates notification using <code>runOnUiThread</code> but it also get killed on application termination.
  Thank you!</li>
  </ul>
  
  <p><strong>Edit</strong> :
  following <a href="https://stackoverflow.com/a/55106058/9005383">m0skit0's Answer</a>
  in the onCreate method, i have created a notification that will be visible during the whole downloading process, showing the number of downloads waiting to handled while it shows an other notification with progress for each downloading process. by calling <code>startForeground(ID, notification)</code> in onCreate, the service will be available even the app is killed. </p>
  
  <ul>
  <li><p>Here's my new <strong>onCreate()</strong> method :</p>
  
  <pre><code>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)
  </code></pre>
  
  <p>}</p></li>
  </ul>