Reputation: 41347
This question brought up an interesting issue.
The OP has an app that displays a map, and this map needs to be updated with location markers that are received via SMS messages. The individual steps are fairly straightforward: the SMS messages can be received by a BroadcastReceiver
, the markers can be displayed by an ItemizedOverlay
on top of a MapView
. The tricky part is to have the receiving part communicate with the main part of the app.
What happens if the app has an active MapActivity
, and then its BroadcastReceiver
is invoked as a response to an incoming SMS? Is the MapActivity
suspended while the BroadcastReceiver
code is executed in the same process? If so, is it safe for BroadcastReceiver
to access the MapActivity
via a static reference (which is set by the activity's onCreate
method?
Conversely, is an app's BroadcastReceiver
executed in a separate process, and would therefore need some other way to communicate with the app's activty?
Upvotes: 3
Views: 4220
Reputation: 38324
Reading the docs, it looks like a BroadcastReceiver is executed on a different process, tho I'm not 100% sure (BroadcastReceiver lifecycle)
A process that is currently executing a BroadcastReceiver (that is, currently running the code in its onReceive(Context, Intent) method) is considered to be a foreground process
This said, I wouldn't consider safe to access the activity from the onReceive, as it's a different process and it will probably crash.
Take into account that the Activity can also act as a BroadcastReceiver, tho you have to control when in its lifecycle it actively listens for events. That way, you can subscribe in onResume (code extracted from ZXing project)
public void onResume(){
activity.registerReceiver(powerStatusReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
[...]
}
public void onPause() {
[...]
activity.unregisterReceiver(powerStatusReceiver);
}
And you define the BroadcastReceiver as a private class inside the public class
final class InactivityTimer {
[onResume, onPause, rest of the stuff ...]
private final class PowerStatusReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent){
if (Intent.ACTION_BATTERY_CHANGED.equals(intent.getAction())) {
// 0 indicates that we're on battery
// In Android 2.0+, use BatteryManager.EXTRA_PLUGGED
int batteryPlugged = intent.getIntExtra("plugged", -1);
if (batteryPlugged > 0) {
InactivityTimer.this.cancel();
}
}
}
}
}
So, the BroadcastReceiver should always persist the new markers (through a Service, never inside the onReceive) AND it should notify a potentially active MapActivity that new markers have been added, which will be listening if it's active.
Or, even easier, the Activity and the BroadcastReceiver listen for the same SMS Intent. While the latter persists it, the first updates the map, tho I'm just guessing what I would try.
Upvotes: 4
Reputation: 41347
The best approach, as others have pointed out, seems to be to create a separate intent that is private to the app. Instead of declaring it in the manifest, the activity registers it whenever it is active. This answer explains how to this.
The public BroadcastReceiver
(which is declared in the manifest and handles the android.provider.Telephony.SMS_RECEIVED
) should then invoke this application-specific intent.
Upvotes: 0
Reputation: 36302
The BroadcastReceiver
should run in the same process. BroadcastReceiver
is designed to be short-lived. As such it can execute without any real worry about suspending the foreground Activity
. You could potentially access the Activity
directly via static reference assuming you checked for the case where the Activity
has not yet been created. However, it might make more sense to communicate via Intents.
Upvotes: 1