I have successfully implemented Firebase messaging in my app. Works great in the background and onMessageReceived() gets called when the app is in the foreground (yippee!).
The issue I have is that I need to update the UI dynamically and I am stuck on the best way to achieve this. I don't want to send the user an in-app notification (as the sample code shows), I'm not sure I want to send a broadcast, all I want to do is to access the MainActivity in order to call a method already there, however I have no reference to the MainActivity in the service.
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
if (remoteMessage.getNotification().getBody() != null) {
Log.d(LOG_TAG, "Message received: " + remoteMessage.getNotification().getBody());
} else {
Log.d(LOG_TAG, "Message received: " + remoteMessage.getData().get("message"));
}
// Call method in MainActivity
// <<< What goes Here?>>>>
}
This seems a simple use case but I can't find anything online to help.
Thanks in advance
Yes, you can update UI and pass value to your activity by using Local Broadcast
In your onMessageReceived() Firebase Service.
broadcaster = LocalBroadcastManager.getInstance(getBaseContext());
Intent intent = new Intent(REQUEST_ACCEPT);
intent.putExtra("Key", value);
intent.putExtra("key", value);
broadcaster.sendBroadcast(intent);
and register local Broadcast in your Activity or fragment method
#Override
public void onStart() {
super.onStart();
LocalBroadcastManager.getInstance(getActivity()).registerReceiver((receiver),
new IntentFilter(PushNotificationService.REQUEST_ACCEPT)
);
}
#Override
public void onStop() {
super.onStop();
LocalBroadcastManager.getInstance(getActivity()).unregisterReceiver(receiver);
}
and Handle Your update event like this, do your update UI work Here, it will call automatically when notification received and onMessageReceived() send a broadcast.
receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
try {
String value= intent.getStringExtra("key");
String value= intent.getStringExtra("key");
} catch (Exception e) {
e.printStackTrace();
}
}
};
I believe you should send a Local Broadcast with the data and register a receiver wherever you want that data to be utilised. This is a very good design pattern(Observer) as it decouples your Activity from the Service.
If the activity wants to do something with the data it will, else it won't. They are both separate entities and it would be much easier to maintain this code in the future, as far as I know.
Hope this helped.
Related
i am having a group chat feature.every person in the group will receive the push(even the sender of the message).
if the person has opened the group i.e the chatting area is visible, then i want that the push does not show up in the notification bar and it directly update the chat (which i am showing in a listview ).
Initially the chat history i get from web service (when the user open the chat area)
Hope i am able to make you guys clear with what i want to achieve .thanks in advance
First of all, when you get message in onMessage() of GCMIntentService, send brodcast. Like,
Intent i = new Intent();
i.setAction("appendChatScreenMsg");
i.putExtra("sender_id", b.getString("sender_id"));
i.putExtra("message", b.getString("message"));
i.putExtra("time", getCurrentTime());
i.putExtra("date", getCurrentDate());
this.sendBroadcast(i);
Next, Make BroadcastReceiver in your Chat activity or Chat Fragment. Like,
BroadcastReceiver appendChatScreenMsgReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Bundle b = intent.getExtras();
if (b != null) {
int totalItems = adapter.getCount() - 1;
ChatModel model = new ChatModel("" + sharedPreferences.getString(VariableBag.USERID, ""), ""+ b.getString("sender_id"), "" + b.getString("message"), b.getString("date"), b.getString("time"));
arrChat.add(model);
if (adapter != null) {
if (lstChat.getLastVisiblePosition() == totalItems) {
adapter.notifyDataSetChanged();
lstChat.setSelection(adapter.getCount());
} else {
adapter.notifyDataSetChanged();
}
} else {
adapter = new ChatAdapter(getActivity());
lstChat.setAdapter(adapter);
adapter.notifyDataSetChanged();
lstChat.setSelection(adapter.getCount());
}
}
}
};
Next, Register BroadcastReceiver in onCreate(). Like
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getActivity().registerReceiver(this.appendChatScreenMsgReceiver, new IntentFilter("appendChatScreenMsg"));
}
Next, unregisterReceiver in onDestroy(). Like,
#Override
public void onDestroy() {
super.onDestroy();
getActivity().unregisterReceiver(appendChatScreenMsgReceiver);
}
Explanation :
1.) When message is received in GCMIntentService(), first of all, check weather
you are in chat screen or not.
2.) If you are in chat screen, broadcast your message using Intent and Broadcast.
3.) Now, Create your BroadcastReceiver() in chat screen.
4.) Register your BroadcastReceiver() in onCreate() and unregister in onDestroy().
5.) When message is broadcast and you are in chat screen, this broadcast receiver get your bundle.
6.) Now Whatever you want to do.
7.) If you are not in chat screen, then show respected message in notification. Don't broadcast.
Note: Be sure in which screen you are currently.
I think you should use Observer Design Pattern.
set a listener where you display messages and in your service where you get your messages from server check for listener, if listener wasnt null call a update method from listener and update your list else show notification.
example of this patern :
http://www.vogella.com/tutorials/DesignPatternObserver/article.html
I want to know how to push notification with out letting user know that a push notification is received.Just my application should be aware of the notification and do the task required depended upon notification.
public class GCMIntentService extends GCMBaseIntentService
{
#Override
protected void onMessage(Context context, Intent intent)
{
Log.i(TAG, "Received message");
if (intent.getExtras().containsKey("payload"))
{
String message = intent.getExtras().getString("payload");
CommonUtilities.displayMessage(context, message);
// notifies user
//generateNotification(context, message);
}
}
}
here in this method dont notify user when the message comes.
EDIT:
this answer is applicable only if you have used GCM directly in your app implemented by yourself.
If you are using parse.com for this then you cant achieve what you have asked in question. because parse API internally notifies this user.
I am trying to develop a android chat application using asmack api and server is openfire.
I am at the stage of handling incoming messages from users and representing them corresponding user chat screen (i.e. activity).
So for that, I developed 2 activities i.e.
public class ResultActivity extends Activity
public class UserActivity extends Activity
resultactivity is the one which maintains roster presence information like online , away etc. so this would be only one instance.
useractivity is the one which maintain chat list with the corresponding user. This activity starts with onclick event on list in ResultActivity. so this can be more than one based on no of users on Result activity..
So to listen to incoming packets (i.e. incoming messages) I added a listener in the ResultActivity which adds messages into global arraylist.
In Result Activity:
PacketFilter filter = new MessageTypeFilter(Message.Type.chat);
MainActivity.connection.addPacketListener(receive_message, filter);
PacketListener receive_message = new PacketListener() {
public void processPacket(Packet packet) {
message = (Message) packet;
String sender=null,body=null,sender_final=null;
if (message.getBody() !=null) {
Log.d("UA", "message from "+StringUtils.parseBareAddress(message.getFrom()));
Log.d("UA", "message is "+message.getBody());
sender = StringUtils.parseBareAddress(message.getFrom());
sender_final=sender.substring(0, sender.indexOf('#'));
body = message.getBody();
Log.d("UA", "Sender : "+sender_final+" body : "+body);
userMessage = new UserMessage("In", sender_final, body);
userMessage_list.add(userMessage);
userMessage_list.add(userMessage);
}
}
};
After adding the message in the global message list (i.e. userMessage_list) I need to update the user activity with incoming message. userMessage_list is the array list used as array in the getview method of base adapter extended class.
So Now I need the update the userActivity list with notifydatasetchanged method.
In UserActivity :
private class UserActivityThread extends Thread {
#Override
public void run() {
UserActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
userAdapter.notifyDataSetChanged();
}
});
}
}
So how to call the notifydatasetchanged method in the another activity.
I am curious to know how this scenario is handled in whatsapp or any chat applications.
I have solved this problem in my chat app by using a ContentProvider class and a CursorLoaderwhich will be automatically notified everytime certain URI has new records.
In your case I would recommend you launching a broadcast message. Your class which has a ListView with the messages will have registered a BroadcastReceiver and it will be listening to possible updates. Everytime your BroadcastReceiver.onReceive is triggered in your activity, refresh your adapter.
Hope it helps :)
EDIT
How to achieve this:
Create a BroadcastReceiver object in your activity.
BroadcastReceiver mReceiver;
Code your broadcast receiver (on your onCreate for example)
mReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
//extract our message from intent
String extra= intent.getStringExtra("extra");
Log.i("msg received: ", extra);
}
};
Add IntentFilter (in your onResume could be valid)
IntentFilter intentFilter = new IntentFilter("com.myproject.myintentfilter");
4.1 register your receiver
#Override
protected void onResume() {
// TODO Auto-generated method stub
super.onResume();
registerReceiver(mReceiver,intentFilter);
}
4.2 Unregister your receiver
#Override
protected void onPause() {
// TODO Auto-generated method stub
super.onPause();
this.unregisterReceiver(mReceiver);
}
Make sure your receiver will receive the message, cheking that your sendBroadcast matches the IntentFilter.
Finally:
Intent i = new Intent("com.myproject.myintentfilter").putExtra("extra", "This is a new value");
this.sendBroadcast(i);
EDIT 2
In the case of receiving a message during your activity rotation (receiver is not registered) I have found 2 solutions which I am not very satisfied with, but they work.
Reload your listview after orientation change, as the activity destroys itself, you can just reload the information of your listview, your new message should appear anyway.
Put a static field in your activity, everytime you receive a message, put such variable to TRUE. If your broadcastReceiver triggers, put that variable to false, and when your onResume / onCreate method is called after a change of orientation, check your static variable and do your reload if the variable was true (put it to false after reloading the ListView).
app sent transaction to the server, user closes app, now a message needs to be
sent back to the phone from the server 10+ minutes later. The phone may be asleep, or the user might be checking his email. The question which I have is:
how can the phone be notified that a message has been received from server ?
how to display that message ?
A possible solution would be Google cloud messaging, but I still am not able to answer these 2 questions
1) You have to use SERVICE for that.
2) And to show that message.
Do like this.
The variable and method are members of Service class:
public final static String ACTION = "com.apps.example.MainActivity";
private void messageFromServer()//this method sends broadcast messages
{
Intent intent = new Intent(MOVEMENT_UPDATE);
String messageFromServer=serverMessage //here you will put server message
intent.putExtra("MessageFromServer", messageFromServer);
sendBroadcast(intent);
}
And this are the methods from Main activity:
You have to register receiver in the onResume method:
#Override
public void onResume()
{
IntentFilter intentFilter;
intentFilter= new IntentFilter(YourService.ACTION);
messageFromServer= new MessageFromServer();
registerReceiver(messageFromServer, intentFilter);
startYourService();
super.onResume();
}
private void startYourService()
{
startService(new Intent(this, YourService.class));
}
public class MessageFromServer extends BroadcastReceiver
{
#Override
public void onReceive(Context context, Intent intent)
{
// this method receives broadcast messages.
// Be sure to modify AndroidManifest.xml file in
// order to enable message receiving
String messageFromServer = intent.getStringExtra("MessageFromServer");
updateGUI();// here you can update the ui
}
}
and put service in you manifest file.
<service android:name="com.apps.service.YourService" ></service>
I have a service which is running in the background and an Activity that opens up every couple of minutes. When the activity opens the user pushes a button which needs to send a message to the service. The problems is that after the user pushes the button the activity closes. It appears that the activity is closing before the Activity can bind to the service so I am not able to send a message using my Messenger.
Is the best way to handle this to have the service listen to a broadcast receiver and then trigger that broadcast from my activity?
Thanks for any help you can offer!
-Nathan
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.end_activity_button:
endActivity();
break;
}
}
private void endActivity() {
sendMessageToService(ActivityService.MSG_CANCEL_ACTIVITY);
getActivity().finish();
}
/**
* Send data to the service
*
* #param intvaluetosend The data to send
*/
private void sendMessageToService(int intvaluetosend) {
if (mIsBound) {
if (mServiceMessenger != null) {
try {
Message msg = Message.obtain(null, intvaluetosend, 0, 0);
msg.replyTo = mMessenger;
mServiceMessenger.send(msg);
} catch (RemoteException e) {
}
}
}
}
Edit I have implemented Ricardo's solution but I am using localbroadcasts. Everything is now working properly. Thanks for the help!
Is this mServiceMessenger a service of yours to send a message? I have exactly the same scenario as you but I do it differently.
On my Service, I register a BroadcastReceiver like in this post: https://stackoverflow.com/a/4805733/362298
Then, in my activity, whenever I need to send a message, I simply call:
Intent myIntent = new Intent("MY_ACTION_FOR_THE_SERVICE_TO_HANDLE");
//Put some extra here
sendBroadcast(myIntent);
I actually do this right before calling finish() on my activity as well. Is there any reason why you are not using sendBroadcast?