3

An application, let us call it Application A, that is installed on my phone produces very interesting data. I am not in control of Application A, but the developers were so kind as to broadcast the interesting information locally, so that other applications (like the one I am building, Application B) can work with the data produced by the other application.

I am registering a BroadcastReceiver via the following code in the onResume() of my MainActivity:

registerReceiver(new CustomBroadCastReceiver, new IntentFilter("com.intent.filter.DATA"));

This works perfectly fine, until my application is either force stopped or stopped by Android (presumably to preserve power/free up memory?).

However, Application A produces data all day and all night long. Based on this data, Application B calculates further results and is supposed to sound an alarm, as soon as the readings go in the wrong direction. It is imperative that the BroadcastReceiver in Application B can sound an alarm at any point in time.

What is currently best-practice to keep the BroadcastReceiver alive as long as possible (maybe even surviving a force stop (swiping away) of the application by the user)?

Edit: I found out, months later, that my Samsung phone had put my application in a power saving list of apps that it will forcefully and regularly kill to preserve power. Make sure your application is not in a similar list on your own phone.

Marco7757
  • 735
  • 9
  • 16

2 Answers2

0

You need to register your receiver in your manifest, not programmatically. See: https://developer.android.com/guide/components/broadcasts#manifest-declared-receivers

However, if you target Oreo+, you won't be able to do that anymore. App A would need to explicitly call out your package for the broadcast to be received by an receiver declared in App B's manifest. You can read for about that here: https://developer.android.com/about/versions/oreo/android-8.0-changes#back-all

This isn't a great way for your apps to share data (and hence why Google are phasing it out). It's inefficient to have to load your app into memory each time something happens in another app. Imagine tens or hundreds of apps doing the same thing for all manner of broadcasts, and what that means for battery life.

A better way would be for App A to expose the data in a content provider, and your app to wake up (infrequently) and pull the data.

Jeffrey Blattman
  • 22,176
  • 9
  • 79
  • 134
  • In theory, what prevents me from starting up another `BroadcastReceiver` with the `AlarmManager` every hour or so, and in this `BroadcastReceiver` register the original receiver? – Marco7757 Feb 12 '19 at 09:14
  • 1
    That won't work. As soon as your `onHandleIntent()` returns, your process will be a top candidate to be reclaimed since there's nothing prioritizing it from Android's point of view. The amount of time that takes will vary. – Jeffrey Blattman Feb 12 '19 at 20:51
  • It turns out that the developers of Application 1 call `setPackage()` with a string that I can define freely (Application 1 is open-source). So I set this string to my package name and now register the receiver with intent-filters in the manifest. Nonetheless, the receiver was not updating all night long. Do you have any idea why this could be? Do I have to consider something else than just being called explicitly with `setPackage()`? – Marco7757 Feb 15 '19 at 14:38
  • I believe you need to use `setComponent()` to fully qualify the targeted component. You'd be well served to add a hook into App 1 to force it to send it's broadcast so you can test this easier. Or create a test harness that broadcasts the same intent. – Jeffrey Blattman Feb 15 '19 at 18:08
  • How can I make the app waking up indefinitely without this waking up process getting killed after a day or two? – Cornelius Roemer Jan 01 '20 at 20:27
  • @CorneliusRoemer barring being a system app requiring your app to be installed with the system image, you cannot. Android is a mobile OS it's not expected to have the RAM to hold processes in memory persistently. You can use JobScheduler to wake up periodically, or listen for implicit broadcasts (or the ever shrinking set of explicit broadcasts that you are allowed to listen for in your manifest). – Jeffrey Blattman Jan 02 '20 at 21:03
0

You need to register your BroadcastReceiver in the app manifest file AndroidManifest.xml

<receiver android:name=".CustomBroadCastReceiver"  android:exported="true">
    <intent-filter>
        <action android:name="com.intent.filter.DATA"/>
    </intent-filter>
</receiver>

The system package manager registers the receiver when the app is installed. The >receiver then becomes a separate entry point into your app which means that the >system can start the app and deliver the broadcast if the app is not currently running. https://developer.android.com/guide/components/broadcasts#manifest-declared-receivers

Which means that the system will launch your BroadcastReceiver even if you app is closed, unless your app was force stopped by the user https://stackoverflow.com/a/9240705/1905761

You need to keep in mind though that some restrictions are applied starting from android 8.0 (Oreo) https://developer.android.com/guide/components/broadcasts#changes-system-broadcasts