Can one BroadcastReceiver be used for multiple IntentServices? - android

Normally for a single IntentService you can define the broadcast receiver listener like this in an Activity's onCreate() method (for example)
broadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
//get stuff from the intent and do whatever you want
}
};
And you register the receiver like this (also in onCreate()):
LocalBroadcastManager.getInstance(this)
.registerReceiver(broadcastReceiver, new IntentFilter("my_intent_service"));
And then you start the IntentService with:
Intent intent = new Intent(this, MyIntentService.class);
startService(intent);
And in the IntentService you send messages back to the receiver with:
Intent broadcastIntent = new Intent("my_intent_service");
broadcastIntent.putExtra("whateverData", whateverData);
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcastIntent);
which triggers the onReceive method described earlier.
And then to unregister the receivers, in onDestroy method you can do:
LocalBroadcastManager.getInstance(this).unregisterReceiver(broadcastReceiver);
In the Manifest file, you add for your service:
<service
android:name=".MyIntentService"
android:exported="false" />
I want to receive broadcasts from multiple IntentServices in the same Activity.
Do you need one receiver per IntentService? As in, if I make n IntentServices do I need to register n receivers, make n listener, and unregister n receivers in onDestroy?

The way to filter multiple actions with one BroadcastReceiver is to add them to the IntentFilter:
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("my_intent_service1"); // Action1 to filter
intentFilter.addAction("my_intent_service2"); // Action2 to filter
LocalBroadcastManager.getInstance(this).registerReceiver(mBroadcastReceiver, intentFilter);
And in your BroadcastReceiver:
private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals("my_intent_service1")) {
// Action 1
} else if (intent.getAction().equals("my_intent_service2")) {
// Action 2
}
}
};

yes you can use one broadcast receiver in one activity, that would handle multiple intents from different services.
I’d recommend to add multiple intent-filter to your broadcast receiver to make distinction from which Service you are getting a broadcast.

Related

Android registerReceiver with Intent filter: Do I need to check the action?

Let's say I have this receiver:
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
if(ACTION.equals(intent.action)){
doSth()
}
};
I then register it dynamically like that:
mContext.registerReceiver(mReceiver, new IntentFilter(ACTION));
Do I need to check inside the receiver with
if(ACTION.equals(intent.action)){
doSth()
}
since inside the method registerReceiver I put an intentFilter with ACTION?
You do not need to check for action assuming your filter is correct. As per documentation, "The receiver will be called with any broadcast Intent that matches filter, in the main application thread". More info: https://developer.android.com/reference/android/content/Context.html#registerReceiver(android.content.BroadcastReceiver,%20android.content.IntentFilter)

Broadcast by Notification Action not handled in BroadcastReceiver inside Service

I am trying to build a notification while a music playback service is running and use the notification to interact with the service (play, pause, stop) using the Broadcast mechanism.
(I know there is also the possibility to use PendingIntent.getService() as an action button in the notification, but I don't like this idea, because this would trigger the onStartCommand() of the service and I need to parse and analyze the Intent object to take action, which seems not as clean as the BroadcastReceiver approach, described below).
Let's illustrate what we have so far with some (truncated) code.
We are creating a Notification object inside the service lifecycle, add an action button, and showing the notification using startForeground().
...
Intent i = new Intent(getBaseContext(), PlayerService.class);
PendingIntent piStop = PendingIntent.getBroadcast(getBaseContext(), 1, i, PendingIntent.FLAG_ONE_SHOT);
NotificationCompat.Action actionStopPlayback = new NotificationCompat.Action(R.drawable.ic_stop_white_36dp, "Stop playback", piStop);
notification.addAction(actionStopPlayback);
...
Then we are registering a BroadcastReceiver inside the onCreate() of the service (and unregistering it in onDestroy of course; this is a more simplified example).
IntentFilter intentFilter = new IntentFilter();
registerReceiver(new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Log.d(getClass().toString(), "Broadcast received");
}
}, intentFilter);
And the final result is that the onReceive() of the receiver is never called. The service is a continuous one and is active when the Notification action sends the broadcast. Since I have no way of debugging broadcasts due to their nature, I'm kind of blocked here.
You're creating this explicit Intent for the PendingIntent:
Intent i = new Intent(getBaseContext(), PlayerService.class);
This won't work for a couple of reasons. Explicit Intents - those created for a specific target class - do not work with dynamically registered Receiver instances. Also, this is targeting the wrong class. A broadcast Intent with a Service class target will just fail outright. A getBroadcast() PendingIntent would need a BroadcastReceiver class as the target.
With your current setup - the dynamically registered Receiver instance - you'll need to use an implicit Intent; i.e., an Intent with an action String, rather than a target class. For example:
Intent i = new Intent("com.hasmobi.action.STOP_PLAYBACK");
You would then use that action String for the IntentFilter you're using to register the Receiver.
IntentFilter intentFilter = new IntentFilter("com.hasmobi.action.STOP_PLAYBACK");
Do note that an IntentFilter can have multiple actions, so you can register a single Receiver to handle several different actions.
Alternatively, you could stick with using an explicit Intent, and statically register a BroadcastReceiver class in the manifest. For example:
public class NotificationReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
...
}
}
In the manifest:
<receiver android:name=".NotificationReceiver" />
Then your Intent would be similar to:
Intent i = new Intent(PlayerService.this, NotificationReceiver.class);
However, this would require an additional step, as you would then need to somehow pass the broadcast info from NotificationReceiver to the Service; e.g., with an event bus, LocalBroadcastManager, etc.

android - unable to receive broadcast from a background service

I was working with broadcast receiver and background services. So, When one my activity goes onPause(), I start my service and service sends a broadcast. Now, my broadcast receiver is in the same class as my service. I am receiving my service call, but I am unable to receive the broadcast info. Here is the code I have been working on..
[EDITED]
private String notifier = "ninja.ibtehaz.thenewproject.Activities.activityNew";
#Override
protected void onHandleIntent(Intent intent) {
boolean flag = ProjectApp.getInstance().isActivityVisible();
Log.e("rainbow", "onHandleIntent");
if (!flag) {
//start emergency activity
Log.e("rainbow", "starting activity");
Intent broadcastIntent = new Intent(notifier);
sendBroadcast(broadcastIntent);
}
}
[EDITED] on activityNew class >
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.e("rainbow", "In Method: Service started");
IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON);
filter.addAction(Intent.ACTION_SCREEN_OFF);
registerReceiver(receiver, filter);
}
private BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Log.e("rainbow", "In Method: onReceive");
if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
Log.e("rainbow","Screen went OFF");
}
if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
Log.e("rainbow","Screen went ON");
}
}
};
and the manifest file : [EDITED]
<service android:name=".Activities.ServiceBackground">
</service>
<receiver
android:name=".Activities.ActivityEmergency"
android:theme="#android:style/Theme.NoDisplay">
</receiver>
here is my logcat info :
E/rainbow: onHandleIntent
E/rainbow: starting activity
I am not getting anything after that..
I know this might not be the best practice, I just started working with these things.
Thank you for your help. Cheers!
You are registering a BroadcastReceiver with an IntentFilter which only contains Intent.ACTION_SCREEN_OFF and Intent.ACTION_SCREEN_ON, but no ninja.ibtehaz.thenewproject.Activities.activityNew. It means this BroadcastReceiver can only be invoked when Intent.ACTION_SCREEN_OFF or Intent.ACTION_SCREEN_OFF is broadcast.
Now pay attention to your sendBroadcast code:
Intent broadcastIntent = new Intent(notifier);
sendBroadcast(broadcastIntent);
You are broadcasting an action "ninja.ibtehaz.thenewproject.Activities.activityNew", which can't match the IntentFilter bound with the BroadcastReceiver you have registered.
Try to use these codes:
IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON);
filter.addAction(Intent.ACTION_SCREEN_OFF);
filter.addAction(notifier);
registerReceiver(receiver, filter);
Broadcast Limitations : With limited exceptions, apps cannot use their manifest to register for implicit broadcasts. They can still register for these broadcasts at runtime, and they can use the manifest to register for explicit broadcasts targeted specifically at their app.
Android documentation: https://developer.android.com/about/versions/oreo/background
Try registering like below dynamically in Application Activity/Service instead of Manifest.
BroadcastReceiver receiver = new NotificationReceiver();
IntentFilter filter = new IntentFilter();
filter.addAction(ACTION_UPDATE_NOW);
context.registerReceiver(receiver, filter);
You are registering your receiver inside the processing an intent method ;-) This would not work, definitely.
You must register your receiver earlier, ex. in onCreate() method.

Android Broadcast

There are some question about Android4.2 Broadcast,
android.intent.action.TIME_TICK
android.intent.action.PACKAGE_INSTALL
This two protected broadcast are define in /frameworks/base/core/res/AndroidManifest.xml
Only find where register Receiver use Context.registerRecriver(),
Question:Where to send this Broadcast attached android.intent.action.TIME_TICK
Thanks
If you declare in manifest file it wont be enough.Manifest file is like a blue print.You need to declare the broadcast receiver there and after that u need to register the broadcast receiver in your code here i am attaching sample broadcast receiver code.
batteryLevelFilter= new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
this.registerReceiver(batteryLevelReceiver, batteryLevelFilter);
BroadcastReceiver batteryLevelReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
//yourcode
}
};
You cannot receive this through components declared in manifests, only by explicitly registering for it with Context.registerReceiver().
And it only be sent by the system.
You have to register this intent programmatically : Sent every minute.
like this
IntentFilter if = new IntentFilter(Intent.ACTION_TIME_TICK);
registerReceiver(YourReceiver, if);

Send a broadcast only to specific Activity

I have one Activity which creates a BroadcastReceiver with an IntentFilter in the method onCreate(...):
IntentFilter iFilter = new IntentFilter("action");
receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
}
};
registerReceiver(receiver, iFilter);
On the other side is an IntentService, which shall send some data:
Intent intent = new Intent(getApplicationContext(), receiver.class);
intent.setAction("action");
[...]
sendBroadcast(intent);
But it seems not to work. No Broadcast ist received.
My service class is in an android lib, perhaps this makes trouble.
Thanks for any advices.
Just create the intent with your action.
Intent intent = new Intent("action");
[...]
sendBroadcast(intent);
And consider renaming "action" to something more meaningful, like "com.my.package.actions.SOME_ACTION".
If you only want that your application components receive the broadcast then use:
Register a permission in your Manifest with a signature protection level (and define a use-permission for that permission). More here.
Use sendBroadcast(intent, permission), and specify the permission in 1.
if the intent is inside your app only, consider using LocalBroadcastManager

Categories

Resources