Send Notification only if Fragment is visible - android

I am making a Chat App (just for fun). I am using Pushy API for sending message between two users. Following the tutorial available in pushy.me site, the Push Messages are received in a Broadcast Receiver. Well, this part is working fine, but now I am making a notification system like Whats App, that launches a notification bar when user is not in the chat.
My idea is the following: if the chat fragment is visible, just update the Fragment using LocalBroadcastManager sendBroadcast method, else start a Notification.
I'am making this with sucess with the following code:
if (!Utility.isAppInBg(context)) {
Intent chatPushNotification = new Intent(Constants.CHAT_PUSH_NOTIFICATION);
chatPushNotification.putExtra("chat", obj.toString());
LocalBroadcastManager.getInstance(context).sendBroadcast(chatPushNotification);
} else {
if (title != null && msg != null) {
NotificationUtil.notify(context, NOTIFICATION_ID, notifyIntent,
URLDecoder.decode(title, "UTF-8"), URLDecoder.decode(msg, "UTF-8"));
}
}
The problem is that the method isAppInBg uses ActivityManager with getRunningAppProcesses() method, which is discouraged. There is a way to replace this method by another that checks if a Fragment is visible (remember that this check is made in a Broadcast Receiver)? If not, there is a better approach?

This approach is working fine for me .
public class MyActivity extends Activity {
static boolean active = false;
#Override
public void onStart() {
super.onStart();
active = true;
}
#Override
public void onStop() {
super.onStop();
active = false;
}
#Override
public void onPause() {
super.onPause();
active = false;
}
#Override
public void onResume() {
super.onResume();
active = true;
}
and in receiver
if(!MyActivity.active){
//alert notification
}
else{
//send broadcast
}

Related

Android Firebase Messaging: How Update UI from onMessageReceived()

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.

dynamically update listview when a gcm push notification is received without showing it in the notification bar

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

Android Service hanging after returning to the activity

I find this issue very interesting, some might not. Let's hope I get a solid answer.
I have a Fragment, which binds a service in onResume() to automatically refresh the data every 60 seconds while the user is present. My bind() method here...
public void bind() {
if(connected || MainActivity.sRefresherBinding) return;
MainActivity.sRefresherBinding = true;
Log.v(LOG_TAG, "binding...");
mProgressDialog.setTitle("Service Connected!");
mProgressDialog.setMessage("We're almost there!");
Intent bindingIntent = new Intent(getActivity(), Refresh.class);
getActivity().bindService(bindingIntent, mConnection, Context.BIND_AUTO_CREATE);
getActivity().startService(bindingIntent);
}
Corresponding unbind() method here called in onStop()...
public void unbind() {
Log.v(LOG_TAG, "unbinding");
if (connected) {
mRefreshService.terminate();
getActivity().unbindService(mConnection);
getActivity().stopService(new Intent(getActivity(), Refresh.class));
connected = false;
}
}
onServiceConnected() here...
public void onServiceConnected(ComponentName name, IBinder service) {
if(binder != null) binder = null;
binder = (Refresh.LocalBinder) service;
if(mRefreshService != null) mRefreshService.terminate();
mRefreshService = binder.getService();
connected = true;
mProgressDialog.setTitle("Refreshing your data...");
mProgressDialog.setMessage("We are almost there!");
Log.v(LOG_TAG, "Service Connected");
}
My onStartCommand() on Refresh extends Service
public int onStartCommand(Intent intent, int flags, int startId) {
start(new UpdateListener() {
#Override
public void onUpdate(ArrayList<Quote.SingleQuote> newData) {
Intent broadcastIntent = new Intent();
broadcastIntent.setAction(Utility.BROADCAST);
broadcastIntent.putExtra(Utility.QUOTE_INTENT, newData);
sendBroadcast(broadcastIntent);
}
});
if (mHandler == null) {
mHandler = new Handler();
mHandler.post(mRunnable);
}
return Service.START_STICKY;
}
The runnable...
private Runnable mRunnable = new Runnable() {
#Override
public void run() {
refreshMain();
if (mHandler != null)
mHandler.postDelayed(this, MIN_UPDATE_TIME);
}
};
refreshMain is too large, I'll just post the snippet where the result is sent back to the listener...
call.enqueue(new Callback<Quote>() {
#Override
public void onResponse(Response<Quote> response) {
try {
List<Quote.SingleQuote> asList = response.body().query.results.getQuote();
mQuotes = new ArrayList<>(asList);
mListener.onUpdate(mQuotes);
Log.v(LOG_TAG, "Refreshed");
}
And finally my Broadcast Receiver...
public static class UpdateReceiver extends BroadcastReceiver{
#Override
public void onReceive(final Context context, final Intent intent) {
if(MainFragmentService.getInstance().mProgressDialog != null) MainFragmentService.getInstance().mProgressDialog.dismiss();
if(MainFragmentService.getInstance() != null) {
MainFragmentService.getInstance().mQuotes = intent.getParcelableArrayListExtra(Utility.QUOTE_INTENT);
MainFragmentService.getInstance().mAdapter.swapList(MainFragmentService.getInstance().mQuotes);
Log.v(LOG_TAG, "Package received");
MainActivity.sRefresherBinding = false;
}
}
}
Here's the tricky part.
All of this code works beatifully on my nexus 5, but when I run it on my Nexus 7, go into another Activity and come back, the service hangs. The data is fetched, broadcasted, picked up, BUT the dialog doesn't get dismissed and the data is not displayed in the recycler view.
A look at the logcat on my Nexus 5:
V/MainFragmentService: onPause
V/MainFragmentService: unbinding
V/MainFragmentService: onStop
V/MainFragmentService: onResume
V/MainFragmentService: binding...
V/Refresh: RefreshMain called
V/MainFragmentService: Service Connected
V/Refresh: Refreshed
V/MainFragmentService: Package received
Now a look at the logcat on my Nexus 7:
V/MainFragmentService: onPause
V/MainFragmentService: unbinding
V/MainFragmentService: onStop
V/MainFragmentService: onResume
V/MainFragmentService: binding...
V/MainFragmentService: onResume
V/Refresh: RefreshMain called
V/MainFragmentService: Service Connected
V/Refresh: Refreshed
V/MainFragmentService: Package received
V/Refresh: Waiting
V/Refresh: Waiting
V/Refresh: RefreshMain called
V/Refresh: Refreshed
V/MainFragmentService: Package received
In case you have doubts about this code working at all, the app is right here, go nuts. If you read this through, thanks for your time!
Issue tracked down to Developer Options > Apps > Don't keep activities enabled on the Nexus 7, disabled on the Nexus 5 (and others).
Meaning that the real issue was on the Activity itself, which was being destroyed when navigating out of it. When navigating back, a new Fragment was being created on top of the existing one because I wasn't checking the savedInstanceState. The mess mentioned in the comments above is now fixed as well, no need to prevent the activity destruction on configuration changes through the Manifest anymore.
getFragmentManager().beginTransaction().add(R.id.content_main_list_container,
new MainFragmentService(), FRAGMENT_TAG_MAIN_LIST).commit();
Now is...
MainFragmentService mainFragment;
if(savedInstanceState == null) {
mainFragment = new MainFragmentService();
getFragmentManager()
.beginTransaction()
.add(R.id.content_main_list_container,
mainFragment, FRAGMENT_TAG_MAIN_LIST)
.commit();
}

Broadcast receiver not working in some cases

So i have this receiver in my Fragment.class
private BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(WeekplanHepler.ACTION_SERVICE_BINDED) && getUpdateService() != null) {
getCounts();
}
if (intent.getAction().equals(Helper.UpdateCounts)) {
HashMap<String, Integer> counts = (HashMap<String, Integer>) intent.getSerializableExtra(Helper.PARAM_LIST_COUNTS);
// Updating counts
}
}
};
For registering/uregistering this receiver i'm using this code:
#Override
public void onStart() {
super.onStart();
getCounts(true);
getActivity().registerReceiver(receiver, getIntentFilter());
}
#Override
public void onStop() {
super.onStop();
getActivity().unregisterReceiver(receiver);
}
getCounts() is a RetrofitRequest puted in UpdateService, which is getUpdateService() here
So, when retrofit request has been finished, it returns counts through Intent and then, as you see, i'm updating them. But if i go to next Activity and then returns, request will work fine, and it will send intent, but receiver wont get it. I think this can be caused by method service is binded in first place. So i have BaseFragment, which binds service for all Fragments needed
public abstract class BaseFragment<T> extends CustomListFragment<T> {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getActivity().getApplicationContext().bindService(new Intent(getActivity().getApplicationContext(),
WeekplanUpdateService.class), connection, Context.BIND_AUTO_CREATE);
}
}
When i go to next activity, it fragment will bind service, and my previous fragment will call request again, and will have counts. Maybe receiver has some limitations for how much he can get same intents, but i don't think so. Please help
Oh, i forgot to mention how i'm sending intent
sendBroadcast(new Intent(Helper.UpdateCounts).putExtra(Helper.PARAM_LIST_COUNTS, counts));
So, when i've started to use
sendStickyBroadcast(new Intent(Helper.UpdateCounts)
.putExtra(Helper.PARAM_LIST_COUNTS, counts));
instead of
sendBroadcast(new Intent(Helper.UpdateCounts)
.putExtra(Helper.PARAM_LIST_COUNTS, counts));
it worked.

Problem in understanding broadcast receiver

I have an app in which I'm trying to detect WHEN the Internet connection appears and when it disappears.
At the moment, when it appears, I'm starting a new thread (different from the UI) which connects my app to a remote server.
For that I'm hardly trying to implement a broadcast receiver which LISTENS for connectivity, but I'm having problems in understanding the concept.
In my onCreate() I have somethig like:
onCreate()
{
cThread = new Thread(new ClientThread(syncToken));
cThread.start();
}
When there is connection to the Internet I'm sending data through the socket, when there is not I'm storing the data in a database. And when the Internet appears I'm restarting my thread to reconnect and send the old data (which hasn't been sent because of network crashing) and the new one.
Let's say I would implement something like this:
DoRefreshBroadcastReceiver refreshBroadcastReceiver;
...
onResume() {
// register the refreshing complete broadcast receiver
IntentFilter intentFilter = new IntentFilter(DO_REFRESH);
refreshBroadcastReceiver = new doRefreshBroadcastReceiver();
registerReceiver(refreshBroadcastReceiver, intentFilter);
}
public class DoRefreshBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
// call method to run fetch code...
}
}
Does this mean that when the Internet connection is detected my onReceive() gets called? And I could start my thread there?
What is the concept of using an intent? Because I really don't get it. How to use it, and what its purpose?
THE IDEA: I don't really know how to use this intent in this case or how to use it in my app!
Would this thing detect the connection to the Internet even when I'm not in this activity?
EDIT:
Here is how my onReceive looks like:
onCreate()
{
cThread = new Thread(new ClientThread(syncToken));
// cThread.start();
connIntentFilter = new IntentFilter(
"android.net.conn.CONNECTIVITY_CHANGE");
connListener = new MyConnectivityListener();
}
public void onReceive(Context context, Intent intent)
{
mNetworkInfo = (NetworkInfo) intent
.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO);
if (mNetworkInfo != null && mNetworkInfo.isConnected())
{
/*
* if(mNetworkInfo.getType()==ConnectivityManager.TYPE_WIFI);
*
*
* else
*/
cThread.start();
}
else {
System.out.println("There is no internet connection!");
try {
cThread.stop();
}
catch (Exception e) {
e.printStackTrace();
}
}
}
mNetworkInfo != null && mNetworkInfo.isConnected()
Does this mean it's connected or should I verify for a certain type of connection on the emulator?
*I think that I should start my thread directly in onReceive(). As soon as my app starts it detects the Internet connection and BroadcastReceiver gets fired, doesn't it?
Try something like this...
public class MyActivity extends Activity {
private MyConnectivityListener connListener = null;
private IntentFiler connIntentFilter = null;
private Boolean connIntentFilterIsRegistered = false;
#Override
protected void onCreate(...) {
...
connIntentFilter = new IntentFilter("android.net.conn.CONNECTIVITY_CHANGE");
connListener = new MyConnectivityListener();
}
#Override
protected void onResume() {
...
if (!connIntentFilterIsRegistered) {
registerReceiver(connListener, connIntentFilter);
connIntentFilterIsRegistered = true;
}
}
#Override
protected void onPause() {
...
if (connIntentFilterIsRegistered) {
unregisterReceiver(connListener);
connIntentFilterIsRegistered = false;
}
}
protected class MyConnectivityListener extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
// The NetworkInfo for the affected network is sent
// as an extra; it should be consulted to see what
// kind of connectivity event occurred.
}
}
}
A BroadcastReceiver is effectively a 'listener' which listens for events either sent by the system or, in some cases, by your own application components.
In this case, the system broadcasts android.net.conn.CONNECTIVITY_CHANGE whenever there is a connection change (connected/disconnected). By registering your BroadcastReceiver to 'listen' for that event, you can get the extra included in the Intent from your BroadcastReceiver's onReceive(...) method and do whatever you need to do accordingly. The extra is a `NetworkInfo object which will contain information about the particular network and whether it is connected or not.

Categories

Resources