3

What is the best way of letting an Android app upload a potentially large file to a server at a request from the user?

I'm currently using an IntentService, in which I call startForeground and update the notification progress periodically, but the service randomly gets killed by the system after about a minute or so.

Here is the relevant code from onHandleIntent :

class BeamService extends IntentService("SSH Beam") {

  override def onHandleIntent(intent: Intent) = {

    ...

    // Start the notification
    startForeground(0,
      builder
      .setTicker("Starting transfer")
      .setContentTitle(filename)
      .setContentText("Starting transfer")
      .setOngoing(true).build
    )

    // Create the session and the monitor
    val session = server.createSession(auth)
    implicit val monitor = Monitor(filename, size)

    // Send the file
    try {
      session.connect
      session.cd(destination)
      session.put(filename, is)
    } catch {
      case e: Throwable => {
        notificationManager.notify(0,
          builder.setProgress(0, 0, false)
                 .setTicker("Transfer failed")
                 .setContentText(e.getMessage)
                 .build
        )
        e.printStackTrace
      }
    } finally {
      session.disconnect
      is.close
    }

    stopForeground(false)
  }
}
F.X.
  • 6,809
  • 3
  • 49
  • 71
  • 1
    You might consider posting the code for the service. Also, bear in mind that `IntentService` has its own background thread (so don't fork your own) and that it does not keep the device awake (see my `WakefulIntentService` for one that does). – CommonsWare Jun 26 '13 at 20:30
  • I added the `onHandleIntent` code. Any ideas? Should I put the service in a separate process, or is it fine to let it stay in the same process as the activity that started it? – F.X. Jun 26 '13 at 20:39
  • "Any ideas?" -- uh, well, that's not Java code, so I'm not real sure what you're doing there. "Should I put the service in a separate process, or is it fine to let it stay in the same process as the activity that started it?" -- having it in the same process should be fine. – CommonsWare Jun 26 '13 at 20:41
  • It's in Scala, so more or less the same, without boilerplate and parentheses. I'm not getting any kind of exception from the service, just "service died" in the LogCat, followed by "scheduling restart", so I assume the system just killed it even though it was in the foreground. – F.X. Jun 26 '13 at 20:44
  • Yeah, that's not supposed to happen, particularly with `startForeground()`. Not sure what's happening to you. – CommonsWare Jun 26 '13 at 20:46
  • Hm. Now it works. using `notify` in my progress monitor caused the service to exit the foreground state. Weird to have to call `startForeground` again to update the notification... – F.X. Jun 26 '13 at 21:46

2 Answers2

1

I found out how to implement that properly :

  • Do not use the notify method from the NotificationManager while you are in foreground. According to this, you have to use startForeground again if you want to update the notification. (This was causing my service to get killed by the system)

  • There's a weird quirk in startForeground that makes it not show notifications if the ID is 0.

  • Finally, I should have thought about it, but this question gives a nice in-depth answer on how to check if the service is indeed in foreground.

(The fantastic flying network monitor from the System Monitor app also helped me a lot to check if the upload was still running while I was starting other apps to try and trigger the "service died" message)

Community
  • 1
  • 1
F.X.
  • 6,809
  • 3
  • 49
  • 71
0

There are a few reasons to use startForeground, but I can't for the life of me think of a reason to use startForeground on an IntentService! An IntentService should be used to do long-running tasks on a background thread, without interruption, from which you want persistent results.

Joe Malin
  • 8,621
  • 1
  • 23
  • 18
  • 1
    And... that's exactly what I want to do. If I don't use ` startForeground` the service gets killed by the system halfway through the download. – F.X. Jun 27 '13 at 05:33
  • Thinking back about it, you might actually be right, especially about the *without interruption* part. I'm trying to find a way to cancel the download halfway through with a notification action button, and according to the docs the `IntentService` will not receive another intent before it has processed the download. According to [this](http://stackoverflow.com/questions/15524280/service-vs-intent-service?rq=1) I may be able to use a `BroadcastReceiver` thought. – F.X. Jun 27 '13 at 20:46