Update: GCM is deprecated, use FCM
How to refresh activity on receiving gcm push notification if my app is open. I have an activity which contains listview filled with data from the server. I want to refresh my activity (here adding one more item to listview) , if I receive gcm push notification(which also contains some data).
One alternative is to add timer that periodically do server requests and update the list adapter data but I don't want these because it will take much resources.
Do I need to add broadcast receiver which will trigger on receiving gcm push which further request for newer server data and update my activity UI?
Dear commentors, please read the question carefully, I only need to refresh the list (if app is open and that particular activity is open) else no need for same.
Took me a few hours to figure it out. Posting here in case anyone anyone else has the same problem.
The idea is that you have to register your activity as a broadcast receiver. The easiest way to do this is like so:
//register your activity onResume()
#Override
public void onResume() {
super.onResume();
context.registerReceiver(mMessageReceiver, new IntentFilter("unique_name"));
}
//Must unregister onPause()
#Override
protected void onPause() {
super.onPause();
context.unregisterReceiver(mMessageReceiver);
}
//This is the handler that will manager to process the broadcast intent
private BroadcastReceiver mMessageReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// Extract data included in the Intent
String message = intent.getStringExtra("message");
//do other stuff here
}
};
The above code goes in the activity that you want to 'listen' for events.
Now, how do we send data to this 'listener'? Go to your push notification handler(or from where you want to update your activity) and when you receive a notification call this function:
// This function will create an intent. This intent must take as parameter the "unique_name" that you registered your activity with
static void updateMyActivity(Context context, String message) {
Intent intent = new Intent("unique_name");
//put whatever data you want to send, if any
intent.putExtra("message", message);
//send broadcast
context.sendBroadcast(intent);
}
When you call the above function, your activity should receive it.
Note: Your activity must be running/open to receive the broadcast intent
Note2: I switched to a library called 'otto'. It does actually the same thing but easier, 'broadcasts events' thoughout the app. Here's a link http://square.github.io/otto/
I'm assuming your GCMBroadcastReceiver is in it's own .java file?
As far as refreshing an activity, I would also like to know the answer to that question.
But for knowing if a particular activity is active or not, meaning on screen just add a boolean (call it something like "active") and set it to true in your activity's onResume() event, and to false in the onPause() event:
protected void onResume()
{
super.onResume();
active = true;;
}
protected void onPause()
{
super.onPause();
active = false;
}
Your active variable would be a boolean which is global or static. This way you know if a particular activity is in "front".
Hope that helps a bit.
The accept answer is indeed correct for the "Refreshing activity on receiving gcm push notification" (I've upvoted it too). But if you only want to update a ListView that's being displayed you don't need a broadcast receiver.
Your GCM listener service can update the database using a ContentProvider rather than inserting a direct sql query.
Then you can rely on the notifyChange method on the ContentResolver to do the trick.
Notify registered observers that a row was updated. To register, call
registerContentObserver(). By default, CursorAdapter objects will get
this notification. If syncToNetwork is true, this will attempt to
schedule a local sync using the sync adapter that's registered for the
authority of the provided uri. No account will be passed to the sync
adapter, so all matching accounts will be synchronized.
If your app is already running then try to override the onNewIntent method
Seems there is an easier way. In the OnMessageReceived method of the GCM Listener, you can just do the update from there instead of sending the notification. You can use the same code you would have used if processing the notification. If you're doing StartActivity from the listener, you have to use the ActivityFlags.NewTask flag.
To sum it up in single sentence:
If you want to refresh activity, broadcast your custom event when notification arrives and register your activity as broadcast receiver of that event
Intent notificationIntent = new Intent(context, MainActivity.class);
notificationIntent.setAction(Long.toString(System.currentTimeMillis()));
PendingIntent.getActivity(context, 0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
Related
I have a Service that frequently updates the Main Activity UI by passing values via a LocalBroadCastManager. The following method is triggered within the Service to pass the value to the Main Activity:
private void updateUI(String statusValue){
broadcastIntent.putExtra("status", statusValue);
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcastIntent);
}
Within the Main Activity I added a BroadcastReceiver to pick up the value and update the UI accordingly:
private BroadcastReceiver mMessageReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// Get extra data included in the Intent
String brStatus = intent.getStringExtra("status");
if(brStatus != null){
//Update UI
}
}
}
};
When the user navigates to another activity the receiver for the Broadcasts is unregistered as the user wont see the UI. Then onResume() when the user returns to the activity the receiver is reregistered:
LocalBroadcastManager.getInstance(this)
.registerReceiver(mMessageReceiver, new IntentFilter("speed-stats"));
UPDATE:
Whilst the activity is paused, the user can make actions (such as 'Pause') by clicking on Pending Intents on the ongoing notification. This action is handled within onStartCommand() of the Service:
case PAUSE_SERVICE :
Log.i(LOG_TAG, "Pause Foreground service.");
startForeground(NOTIF_ID,makeNotification(isRunning = false));
updateUI("paused");
stopSpeed();
break;
This works fine, however i have noticed that the UI is not updated as the receiver is unregistered whilst the activity is paused.
Is it possible to continue these UI updates despite pausing? Or is it possible to apply the UI updates as soon as the activity is resumed?
When the user navigates to another activity the receiver for the
Broadcasts is unregistered as the user wont see the UI.
This is the reason why your Activity's data is not up to date. Since the broadcast receiver is unregistered, data sent by the service won't be received.
Since its not a great idea keep the receiver registered, one solution would be:
Bind the service in on onResume() an unBind() it in onStop().
Inside service maintain data object, which will hold the latest data.
After service is binded, call the service method through Binder which
will return the the data Object with latest data.
Update the data in your Activity accordingly.
You can refer this SO for binding/unbinding service
I want to implement pub/sub in my app, for that server send notification in specific event, I will do some modification on data which is display in my activity
onMessageReceived() doesn't need PendingIntent to be call. It will always call if you have correct setup. This link provide the data type you should sent to FCM server
With FCM, you can send two types of messages to clients:
Notification messages, sometimes thought of as "display messages."
Data messages, which are handled by the client app.
If you would like to always trigger use just data message so it will always trigger the onMessageReceived().If you try to use data-message and notification-message together the onMessageReceived() will not get trigger when your app is in background.
Just do anything you would like to do such as save to database, sharedPeference etc inside your onMessageReceived()
So how you sent to the activity?
Use Broadcast Receiver here is how you sent a broadcast receiver in your case you will like to put it inside your onMessageReceived() so anytime you received a new notification this code will help you sent the data to the specific activity.
Intent intent = new Intent("Use anything you like");
intent.putExtra("data","The data you receive");
sendBroadcast(intent);
In your activity register it in your onStart()
registerReceiver(broadCastReceiver,new IntentFilter("must match the intent filter parameter"));
Here is how you handle your data
class broadCastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Log.d("Your data",intent.getData());
}
}
Note: your intent filter parameter must match the intent parameter you set in your onMessageReceived()
If your app never received data from the FCM this answer will be useless since your question still unclear this is the best I can do for you.
I'm using a BroadcastReceiver in my Android app which simply contains the following piece of code:
public BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
GcmIntentService.isHandled = true;
Toast.makeText(context, "broadcast receiver test", Toast.LENGTH_SHORT).show();
}
}
I'm using this receiver to determine if my activity is running and carry out some updates in a ListView without having any notifications produced by GcmIntentService.
With the code being simple so far, only creating a toast message, I'm unable to catch the boolean value from GcmIntentService.isHandled as soon as the sendBroadcast is invoked.
Is it possible in any way to determine if the code for my receiver has finished running. I understand that sendBroadcast is an asynchronous call, and I'm making use of Thread.sleep(1000) so far to wait for the isHandled value, but it would be nice if there is a more reliable method on achieving this.
Any thoughts?
Your question can be divided to two parts:
1.How to know that if there is a receiver actually received the broadcast.
2.How should the receiver notify the service that message is been handled.
It seems difficult to achieve the first goal through standard Intent api, instead I suggest you may try the "observer pattern".
You may create a global Observable object in your Application and make your Activity implements Observer, register itself in onCreate() and unRegister in onDestory().Inside the Service you can check if there is an Activity running through countObservers() and then simply notify it.
I am working on an application in which I have a background task executing via service. I have a list showing some data elements in it. My Scenario is:
1- User set something to execute in bg and does not close the app and leaves it in this state.
2- Background process starts working, it completes its work and finishes. But list is still showing the task user entered. It should have been removed from the list.
This is the very functionality I want to achieve. How can I achieve that?
Remember if user performs some action like navigate to other screen etc, I have coded it to get new list for view. But if user leaves it idle after scheduling something, view does not refresh. Please help me out of this. Any help is appreciated.
call notifyDataSetChanged() on your list adapter.
notifyDataSetChanged() Notifies the attached observers that the underlying data has been changed and any View reflecting the data set should refresh itself.
Android. How does notifyDataSetChanged() method and ListViews work?. The accepted answer is the link has a good explanation.
I think you have to use Service with BroadcastReceiver to resolve your issue.
// Register Broadcast Receiver
IntentFilter filter = new IntentFilter(MyService.MYOWNACTIONFILTER);
registerReceiver(myReceiver, filter);
In Service you need to send
Intent intent = new Intent();
// Bundle the counter value with Intent
intent.putExtra("key", data);
sendBroadcast(intent); // finally broadcast
after your background operation done.
And finally
in your service calling Activity
private BroadcastReceiver myReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
// do your operation and refresh the list
}
}
Hope this will work.
I'm just getting into Android development, and I have a question about communicating between a receiver class and an activity class. I'm very new to JAVA and Android so I hope I don't sound too stupid. I'm developing an application where I intercept an SMS message and then based on various elements of that SMS I might delete it once it's been saved to the inbox. I have a receiver class that intercepts the txt message, and I am also able to delete messages from my inbox with code in the activity class using a button at the moment. The problem I have is communicating between the receiver class and the activity class where the code to delete a message resides. I tried putting that code directly into the receiver class but as I'm sure most of you already know the BroadcastReceiver class doesn't seem to support what I need to delete messages. I've been searching for an answer to this for a while, but haven't been able to find anything. Honestly I'm not sure I know enough about JAVA and Android to even recognize a solution if I saw it.
If you need to complete a job without an interface look into creating a Service, if you need user interface just start an Activity
You can use the Context parameter of the onReceive method of the receiver to start a new service/activity
You can use Extras to pass params between context. So you can put as extra the message id or entire message and pass it to your service/activity and deal it there.
You could implement the handling messages logic using an IntentService. When your receiver gets the new incomming message, start the IntentService passing an intent with the message data.
Receiver
onReceive(Context context, Intent intent) {
//Setup Intent
Intent i = new Intent(context, MyIntentService.class);
i.setAction(MyIntentService.HANDLE_MESSAGE);
//Pass data to intent
i.putExtra(MyIntentService.MESSAGE_DATA, data);
//Start Intent Service
context.startService(i);
}
MyIntentService
onHandleIntent(Intent i){
String action = i.getAction();
if(action != null && action.equals(MyIntentService.HANDLE_MESSAGE){
//Get data and implement message logic
}
}
Hope it helps.