I'm so lost with all that workflow of notifications and services in Android. My sceneario is this:
I have an Android application that communicate to a MySQL database through a web-service using JSON-RPC. The data retrieved from the service will be displayed in the application.
The data will get updated over time, so the application needs to listen for changes of this and, if a change occur, show a notification and update the data displayed in the app.
To listen for changes I will need to run an "infinite"(until the app is destroyed or maybe until the app destroys it) thread that from time to time will call a method on th web-service which will return the changes since the last check.
UPDATE: Ok, I have been trying using Service and IntentService, but non of them fits my needs: a Service execute in the Main Thread, so If I perform an infinite loop there my app will freeze, IntentService has it's own worker thread but there is no comunication with the App, and I need it, or at least I need a way to know if the app is in foreground (in this case the notification will not popup but the data will be passed and updated) or in background (int this case the notification will pop up and on click it will direct the user to the app with the updated data)
#1 You can fire a broadcast message from your Service and define a Broadcast receiver in your Activity to receive this broadcast.
SEND BROADCAST-from Service
Intent i = new Intent("ALERT_CHANGE");
i.putExtra("DATA","News");
sendBroadcast(i);
RECEIVE BROADCAST-in Activity
registerReceiver(uiUpdated, new IntentFilter("ALERT_CHANGE"));
private BroadcastReceiver uiUpdated= new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent)
{
String DATA = i.getStringExtra("Data");
txt.settext(DATA);
}
};
Ok, after a lot of testing and thanks to the info given here I finally found a way to handle with the issue, so I will share it here:
On the IntentService I have a public static AtomicBoolean to control the end of the loop and be able to stop the service.
Then to determine if the Activity is in foreground or not I use the method suggested here https://stackoverflow.com/a/5504711/3107765
With the difference that I use the static modifier there, so I can check it from the service.
if the activity is in foreground I send a broadcast as it was suggested here by Eu. Dr. otherwise I use a notification that once clicked will let the user to the activity.
Related
Is it possible to send an intent from a service to an Application class? Not Activity?
I wouldn't know what activity would be running at a particular time, so I am adding a boolean flag in the activity class that detects the activity and sends the appropriate data based on the broadcast received.
If your Service is active, then your Application class is active as well.
Otherwise you wouldn't be able to use getApplicationContext().
Although I'm skeptic about a service that runs forever there is a very clean way to make the Service communicate with a certain Activity, should the last one be currently active.
Such clean way is called LocalBroadcastManager.
The Activity meant to receive the data should register a BroadcastReceiver in onResume() and unregister it in onPause().
You instantiate your BroadcastReceiver in your Activity's onCreate()
this.localBroadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// Do what you have to do here if you receive data from the Service.
}
}
You create a Filter so your Activity only listens to a certain type of signals.
private IntentFilter notifIntentFilter new IntentFilter("com.you.yourapp.MY_SIGNAL");
in onResume()
LocalBroadcastManager.getInstance(getApplicationContext()).registerReceiver(this.localBroadcastReceiver, notifIntentFilter);
in onPause()
LocalBroadcastManager.getInstance(getApplicationContext()).unregisterReceiver(this.localBroadcastReceiver);
Now whenever you want to send data to your Activity, your Service can call:
final Intent intent = new Intent();
intent.setAction("com.you.yourapp.MY_SIGNAL");
// put your data in intent
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intent);
If your Activity is awake, it will respond to the signal. Otherwise, if it's in the background, or it is not instantiated it won't.
You can apply this pattern to as many Activities as you wish.
Still, I have never used this inside the Application class. But you can try to register your receiver there. It might work, since if the Application class is destroyed, the BroadcastReceiver is destroyed too and thus probably unregistered as well.
The point is, if your Application gets destroyed, your Service will be killed as well. Unless you launched it in another process. But then it will have it's own instance of Application; and this is a complex thing you probably do not want to get into details now...
Important: since the Application class is not tied to any UI component, you can do whatever you need directly inside your service. If you need to manipulate the UI, then the pattern described above will work for you.
Please read about new Android's background limitations.
Edit:
Oh yeah right, if you need your Service to call a function declared in your Application class, you can just do
((MyApplication) getApplication()).myFunctionToHandleData(Intent intent);
I didn't really understand your question though, but either of the methods described above should work for you.
Project statement:
i have a simple counter app which has 6 things i am counting. on my wearable, i have a radiobutton group which selects which of those things i want to count. it then displays the current count for the item on the watch and then i can either add or subtract 1 from it from the watch. The watch is only an interface and interaction device. it does no processing. All processing of information and storing of information is done on the mobile. so the watch merely sends messages and displays information.
How it works:
the wear sends messages to the mobile via Wearable.MessageApi.sendMessage() and the phone responds with Wearable.DataApi.putDataItem(). The watch is sending multiple forms of informaiton like add/subtract/countRequest in addition to which item it is references. the mobile only responds with the item count requested and the watch only need change the display if it is a different value than what is showing.
This is a general messenger understanding question. I have
public class MyListenerService extends WearableListenerService{
#Override
public void onMessageReceived(MessageEvent me){
showToast();
}
}
The listener works. Now i want to do something useful with the listener because it is actually sending data i need. But i am having trouble communicating between Service and Activity because of my limited experience. I have read up on messaging and broadcast receivers. and am looking for ideas on how to implement to get my result or a better understanding.
From what i am gathering from trying to code, a service cannot directly interact with my interface, so i need to communicate with my activity in some way. 2 ways i have read is messaging(handlers) and broadcastreceivers.
each of these methods will do the function, however have their drawbacks which is where i am looking for better understanding or help.
for the Handler: even though i can create a static handler class and run code within the handler class, because it is static i cannot call non static objects which means if i try and do this it fails.
Service:
public class MyListenerService extends WearableListenerService{
#Override
public void onMessageReceived(MessageEvent me){
Activity.mHandler.sendEmptyMessage(MyConstants.COMMAND);
}
}
Activity:
public static Handler mHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
doThis(msg.what);
}
};
private void doThis(int command){
processCommand();
updateUserInterface();
}
Is there a way i can implement the above Handler, because when i process message if i just simply do a toast, it works, so i can receive the message. I just cant call a non-static object from a static. so i am assuming i cannot update an interface object either if i just threw the code of doThis() inside the Handler since i am just using it as a go between. When i was using LiveListeners and the onMessageReceived() was within my Activity, rather than a separate service, i just called doThis() directly and it worked great.
for the BroadcastReceiver:
There is a lot of code to show so instead i will just explain my issue for it and you may be able to answer from that. apparently you have to register/unregister on onResume()/onPause(). That would prevent me from being able to process information when the phone goes to sleep. the whole point of running a service is so i can do stuff when the phone is asleep or the activity is not in the foreground.
Before i was doing "LiveListeners" and it worked fine, so long as activity was in the foreground and phone was not sleeping. only way to have it work while sleeping is to engage a service to work in the background.
So my question is, what is best way to handle this situation so that i can process the information that the wearable is sending to the mobile while the mobile is asleep. or is there another method to send data i did not find?
If you extend WearableListenerService, you are creating a special Service which runs as part of your app's process. You can use this to communicate with another Service in your app which does all the processing, or use broadcasts (as you noted.) In either case, the Service is running in the context of your process and on the main thread - so if you need to do any heavy processing you'll need to offload it to a background thread.
Since your WearableListenerService is declared in the manifest and its lifecycle managed by Android Wear (by default), it's going to be simplest to either create a secondary Service or use a BroadcastReceiver to do your processing. Just note that "processing" must be lightweight if in a BR. If you use a BR, look into using LocalBroadcastManager as it is more efficient than sending the broadcast via the usual Context.sendBroadcast(). It's roughly the equivalent of sending a message to your app, it just happens to be in Intent form.
I certainly do not want to oversimplify greatly, but I like the easy way. Having intent I just awaken mobile or wearable from Sleep, and then the other threads also perforce awaken and process data.
#Override
protected void onHandleIntent(Intent intent) {
// TODO: This method is called when the BroadcastReceiver is receiving
// an Intent broadcast.
String tmp = " ";
PowerManager.WakeLock wakeLock = null;
// wakeLock.acquire();
if (intent.getAction() != null) {
tmp=intent.getAction();
PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE);
wakeLock = powerManager.newWakeLock((PowerManager.SCREEN_BRIGHT_WAKE_LOCK | PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP), TAG);
wakeLock.setReferenceCounted(true);
if(! wakeLock.isHeld()) {
wakeLock.acquire();
}
Code snippet from https://github.com/NickZt/E52/blob/master/wear/src/main/java/ua/zt/mezon/e52/core/MySpcIntentService.java
I don't know if this is possible, but I would like to do the next:
Imagine an app with 2 activities: MenuActivity and OtherPurposeActivity.
So, on the onCreate method of Menu I had run the Service. In the same Activity (Menu), I can easily "connect"(Edit: communicate) with this Service with no problems.
Then, I click the only button there is on MenuActivity, which starts OtherPurposeActivity. Here comes the question:
How can I connect to the Service I had run on MenuActivity? Is it possible? (I hadn't called stopService).
Thanks in advance.
Edit: Code:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_menu);
/* Execute service */
Log.d("SERVICE", "Launching service");
Intent msgIntent = new Intent(MenuActivity.this, ServerProcessingService.class);
msgIntent.setAction(ServerProcessingService.ACTION_STATUS);
startService(msgIntent);
/* Connection to the IntentService */
IntentFilter filter = new IntentFilter();
filter.addAction(ServerProcessingService.ACTION_STATUS);
//filter.addAction(ServerProcessingService.ACTION_CONTROL);
rcv = new ProgressReceiver();
registerReceiver(rcv, filter);
}
So I can handle the communication with the ProgressReceiver class. But, what if I open another activity, and this service still running? Can I access to it?
How can I connect to the Service I had run on MenuActivity?
Another activity that wants to communicate with the service can use exactly the same method as MenuActivity. startService() will only start the service if it is not already running, and then send the intent to onStartCommand() in all cases, so it is all right to call start service from multiple activities.
As a commenter pointed out, if your activity requires ongoing communication with a service, you should bind to it.
Is it possible? (I hadn't called stopService).
An IntentService will stop itself if it has no work to do, so it doesn't matter that you did not stop it explicitly. If the service needs to continue running, don't use an intent service.
To be on the same page I will describe briefly how I understood your dilemma.
You have an IntentService perfroming some operation which provides at the end some results. You are starting this process in one activity(asynchronously of course) and switch immediately to another one. Now, you are not sure whether service will finish the work before you switch to second Activity and result will be lost.
Basically, approach with BroadcastReceiver would be a good choice but if you won't register on time the data will be lost and service will end it's work. You could let the service to store the result before it ends, in DB, file or even in memory(depending on data type). When your second Activity start you can check if there is data waiting for you, if not you can wait for BroadcastReceiver to deliver it.
You could also use Otto library which is far more advanced solution than BroadcastReceiver. It allows to return to registered observer(Activity) the last result and what is more important it will allow your service to check if any observer received the message. If not you could only then store last result.
So I am trying to make an app so that when a row in a SQL database changes, the user receives a notification even though the app is not currently running. I'm pretty sure this is possible because Facebook can send mobile notifications when the app isn't running, but I'm not sure how to go about this.
You need to use Service which runs in background. From within a service you can start a notification. Its not clear that which 'notification' are you talking about? If you are talking about notification as in Google Cloud Messaging notification, then you need to go a different way. But, then also you would be using
GCMIntentService which extends Service class.
You want to send a notification when when a row in a SQL database changes. Is that row changing on the server side? I am assuming yes because first you were talking about Android database, then you would have mentioned SQLite instead of SQL. Secondly you gave example of Facebook. So, if the answer to my question is yes, then using GCM push services you can send a Push Message to the user. Then when user receives the message, you can show a notification with the proper data. In the onReceive method of GCMIntentService, you will receive the content in an Intent. There you can extract the message and create a notification. See here for more.
You will need to register a content observer to get notified of the changes.
To use the ContentObserver you have to take two steps:
Implement a subclass of ContentObserver
Register your content observer to listen for changes
Notify change from the content provider
--
class DbObserver extends ContentObserver {
public DbObserver(Handler handler) {
super(handler);
}
#Override
public void onChange(boolean selfChange) {
this.onChange(selfChange, null);
// start the notification
}
}
Register your content observer to listen for the changes:
getContentResolver().
registerContentObserver(
SOME_URI,
true,
yourObserver);
Now can call notifyChange after updating your db.
notifyChange(Uri uri, ContentObserver observer)
A quick example of using content observer is https://gist.github.com/JBirdVegas/3874450
You can use Service in android
A service by default runs in the same process in the main thread as the application.
Therefore you need to use asynchronous processing in the service to perform resource intensive tasks in the background. A common used pattern for a service implementation is to create and run a new Thread in the service to perform the processing in the background and then to terminate the service once it has finished the processing.
Each Service has a specific job, and it will run continuously even if you switch between different Activities, or to a different application altogether.
To start a service use the following:
Intent i= new Intent(context, ServiceClass.class);
i.putExtra("KEY1", "Value to be used by the service");
context.startService(i);
A simple example for a service class:
public class ServiceClass extends Service {
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return Service.START_NOT_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
}
My app has a chat screen to send and receive messages. Whenever a message is received a push notification comes in and shows the latest received message. This all works fine.
But when I get my push notification I would like the chat screen to refresh itself. I guess this would require knowing if the chat screen is currently visible or not. How can I do this from the onReceive() method of my BroadcastReceiver?
Here's a little pseudo code (in my BroadcastReceiver subclass):
public void onReceive(Context context, Intent intent)
{
if(currentlyVisibleActivity.getClass() == chatScreenActivity.class())
{
((chatScreenActivity)currentlyVisibleActivity).getMessages();
}
}
I would like to know how to get the currentlyVisibleActvity and make it call getMessages() if it's a chatScreenActivity.
I assume you are planning the following setup?
C2DM -> YourBroadcastReceiver -> somehow call #getMessages()
How about having the following components:
A BroadcastReceiver <for receiving C2DM push notifications>
An IntentService <for executing #getMessages()>
A ContentProvider <for storing the results of #getMessages()>
An Activity <for displaying the contents of ContentProvider>
Basically, C2DM triggers your receiver which calls #startService, triggering
your IntentService.
Your IntentService calls #getMessages() and stores the messages in your
ContentProvider.
Whenever a change is performed on the data in the ContentProvider you will
trigger ContentResolver#notifyChange().
If your Activity is showing and uses, for instance, a CursorAdapter to read
from the ContentProvider it will automatically refresh.
Sending a chat message would also store a row in the ContentProvider in this scenario - automatically updating the UI just as a received message.