I have a service that is activated when alarm is activated. It extends IntentService, and in that service I need to send a message to MainActivity. The MainActivity on receiving this message then performs some necessary work. I send the message to MainActivity using :
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
This works OK if the MainActivity is currently active (displayed). If however the MainActivity is not currently active, I create it using :
PendingIntent mPendingIntent = PendingIntent.getActivity(this, 0,
new Intent(this, MainActivity.class), PendingIntent.FLAG_ONE_SHOT);
mPendingIntent.send(Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY);
If the MainActivity is currently active (displayed), then the message reaches it. However, when I have to re-create the MainActivity using a PendingIntent, the message sent via LocalBroadcastManager does not reach the MainActivity. If I sleep for eg. 2000ms, before sending the message (where the MainActivity has to be recreated), the message does reach the MainActivity.
While this may be understandable, I would prefer to use a fail-safe way of ensuring that the app works as intended.
To guarantee that the MainActivity has received the message, do I need to send a message from the MainActivity to the service to verify that the message has been received?
Is there a better way to handle this?
Is there a better way to handle this?
Only use LocalBroadcastManager when the activity already exists. If you have to start the activity, include the information that you would have sent in the broadcast in the Intent that you use to start the activity. The activity can then look for that information in onCreate() and use it; otherwise, it can behave normally.
Related
I am using Firebase Cloud Messaging and I have my own class that extends FirebaseMessagingService.My activities order are as follows:
SplashActivity -> MainActivity -> DetailsActivity . When the app is in the MainActivity and I send a message using the Firebase Console everything is fine it opens up the Dialog I wanted it to open. Also when I am in MainActivity and I send a message that is meant to open DetailsActivity everything is fine.
However when the app is in the background and I send the message, the Notification does not show as intended and when I click it it opens SplashActivity first even though the defined Intent to be opened using PendingIntent is MainActivity. How can I go about these two problems?
In my custom FirebaseMessagingService class I have defined the Intent to have the following flags Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP and my PendingIntent to have the following flags PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_ONE_SHOT but it still does not work.
Check if method onMessageReceived in your FirebaseMessagingServise is properly called in background, so you can setup what you need.
I had to send data message type instead of notification, because when you send type notification then method OnMessageReceived is not called in background and firebase handles push notification instead of you. Be aware you cannot even combine type notification and data message.
More about data message you can find here https://firebase.google.com/docs/cloud-messaging/concept-options
Is there a way to tell if I reached some Activity through regular flow of the app or whether I reached this (deep) Activity from a Notification via PendingIntent?
I need to perform some operations when the application starts and if I got to this Activity via notification I need to make sure these operations are made.
You can put an extra on your PendingIntent and than when the activity starts check for it using getIntent() ("Return the intent that started this activity."). Doing so you can getExtras() and check how the activity was started.
Is this possible? Currently when I receive a notification OnMessage(Context context, Intent intent) fires, but I'm not able to reference any of my Activities in this context. Is there any way for me to do this? Or do I need the user to click the notification to update the activity and view?
In the OnMessage handler, just execute:
var i = new Intent(this, typeof(MyActivity));
i.SetFlags(ActivityFlags.NewTask);
context.StartActivity(i);
I had a similar problem. You can send a LocalBroadcast inside onMessage. See LocalBroadcast Manager.:
LocalBroadcast Manager is a helper to register for and send broadcasts of Intents to local objects within your process. The data you are broadcasting won't leave your app, so don't need to worry about leaking private data.`
You can send the LocalBroadcast from within the omMessage. Then inside you Activity you can listen to the broadcast which can be with an Intent message. Whenever you receive that local broadcast, you may do the desired action.
See how to use LocalBroadcastManager? on how to implement it. Hope it helps you.
I am implementing a music player. The notifications allow the user to pause or skip a song.
I use
Intent i = new Intent("com.package.app");
mExpandedView.setOnClickPendingIntent(R.id.next_song, PendingIntent.getBroadcast(this, 0, i, 0));
In order to transmit this click to the MusicService that hosts the MediaPlayer and all the associated methods. I would like to directly call a method part of this service (playNextSong() for example) but getService() seems to only allow me to launch a new service, not to call a method in the service, or get some data. I don't even need to launch the service, since the music is playing, it is already running.
So is there a way to do this that I am not aware of ?, or is :
Notification broadcasts to BroadcastReceiver, then BroadcastReceiver broadcasts to the service the recommended way do accomplish this action ?
It looks like a convoluted way to do something simple...
Create PendingIntent for notification as broadcast message, custom one (use your own string like com.my.custom.broadcast.message.action). Create and register in AndroidManifest new broadcast receiver that will be fired by this custom action. OnReceive method of the Broadcast receiver, start your service with custom arguments/action or whatever, based on class of Service and context arguments passed into onReceive method.
Probably you can try to directly start service by creating PendingIntent for that, but I think it is better do it through middle-step: BroadcastReceiver
From the Notification you can start an Activity. That activity would do "bindService" and call the appropriate method in the service, then finish(). The activity doesn't need to have a UI, so the user won't see it. But that's even more code than a Broadcastreceiver.
I have a question regarding AppWidget intent handling. I have a widget which is clickable, and on click I want to send an intent to the AppWidgetProvider itself for further processing.
The problem: I receive the intents initially in onReceive(), but after a while (not sure what causes it), onReceive() is no longer called.
I have the following code, all in MyWidgetProvider extends AppWidgetProvider.
a) register for receiving broadcasts:
in onEnabled(...):
context.getApplicationContext().registerReceiver(this, new IntentFilter(MY_ACTION));
b) set intent to be fired on click:
in onUpdate(...)
Intent intent= new Intent(MY_ACTION);
PendingIntent pendingIntent= PendingIntent.getBroadcast(context, 0/*notusedanyway*/, intent, PendingIntent.FLAG_UPDATE_CURRENT);
views.setOnClickPendingIntent(R.id.widget_root, pendingIntent);
c) react to event and do something:
in onReceive(...)
if (MY_ACTION.equals(intent.getAction())
doSomething();
When I deploy + add a widget, it works fine. However, after a while - not sure what exactly causes the problem, but a phone call, for example, seems to affect it - I no longer get any notifications in onReceive().
I am completely stumped why this is the case. Can someone point out to me the correct way of doing this?
Thanks!
Tom
You should use a BroadcastReceiver registered in your AndroidManifest.xml file. When you register it in onEnable it is tied to the process. Whenever Android kills your process (for example, when a phone call is received) then your receiver no longer exists and (as you observed) no longer works.