0

I have an application that makes async HTTP requests from various places (app activities and a background service). I'd like to catch response events inside my main activity and modify some views. This is achieved by using anonymous class BroadcastReceiver inside the main activity. The registering/unregistering of the broadcast receiver is inside onResume()/onPause().

The problem is that when screen is off and the activity is not in the foreground the events aren't caught, because the receiver is unregistered. How to catch all events even in background while preserving register/unregister coherency of BroadcastReceiver?

bvk256
  • 1,837
  • 3
  • 20
  • 38
  • When the phone screen is turned off, the OS put all opened apps to the `onPause()` state, so you just put `unregister receiver` in `onDestroy()` method of the activity. – diogojme Jan 08 '16 at 11:58
  • @diogojme See this answer https://stackoverflow.com/a/7887433/685948 it explains the problem with this method – bvk256 Jan 08 '16 at 12:07

3 Answers3

2

Your best bet here would be to start a persistent background service (with a local broadcast receiver).

Here are some starting points:

  • Your service's onStartCommand() should return START_STICKY, so it's not killed by the OS.
  • You should create a local variable inside the Service that holds your broadcast receiver and register this receiver in onStart() and unregister it in onDestroy().
  • Start the service whenever you find suitable (e.g. onCreate() of the Application, since it's only called once per application life-cycle and is not tied to a specific Activity).

This answer might help.

Your existing approach doesn't work because when the screen is turned off, the onPause signal is sent to all your activities and they automatically unregister the local broadcast receiver (and they should be).

Community
  • 1
  • 1
Dzhuneyt
  • 8,437
  • 14
  • 64
  • 118
  • But how an activity UI can be modified per event without static references? I mean without `static MainActivity mainActivity` inside for example Application class – bvk256 Jan 08 '16 at 12:19
  • 1
    Communication between a Service and an Activity and between a BroadcastReceiver residing outside of the Activity and an Activity are a whole different topic. You should look into creating a `LocalBroadcastReceiver` instance (separate from the one discussed in this question). One that is used for sending/receiving intents within components of your application. Basically, the idea is that your Activity subscribes to a specific IntentFilter (list of events) in its lifecycle and the Service fires those intents whenever you find suitable (e.g. when its local BroadcastReceiver is triggered). – Dzhuneyt Jan 08 '16 at 13:53
1

There two alternatives

  1. Have a service running and register the receiver there instead.

  2. You can register the broadcast receiver in the manifest and handle it there. Please keep in mind that the receiver will run on the main thread, so you should signal to a running service perhaps a service that performs a single task.

A service that performs a single task can be implemented using IntentService. It is kind of like an async task wrapped in a service.

  • Yes, I've considered this, but hoped there are some simpler ways. Using the proposed alternatives a static reference to the main activity should be placed somewhere, which is not a very good pattern as I know. – bvk256 Jan 08 '16 at 12:14
0

I solved the problem by adding EventBus lib. The handler is implemented inside the main activity, activity subscribes for events on onCreate() and unsubscribes on onDestroy(). Since EventBus lib is built on standard Java components I expect the garbage collector to automatically clean up everything even if onDestroy() is not called.

Futhermore I used WeakReference for my views which allows to check if an activity is already disposed to prevent unexpected errors.

This may be not the best solution, but it works for now and much easier to implement than other proposed answers.

bvk256
  • 1,837
  • 3
  • 20
  • 38