I have the following situation: A service is running in the background of my application and regularly receives UDP packets. It uses an instance of my HandleMessageAgent class which analyses every message and shall start a new activity if necessary.
I would like to perform the following task: No matter which activity is in the front (as long as the service is running) I would like to inform the user about an incoming message under certain circumstances. I also need to update the information regularly as long as it is valid. Afterwards it should be closed automatically.
At first I thought about using a Dialog, but I think I cannot use it when the activity is not visible. Therefore I decided to use an activity, as it can be started from a service all the time.
I want to start the activity within the HandleMessageAgent object (in a method). My problem is, that I do not know how I can define an Intent to start an activity within an object, as the Context is not clear to me.
Is there a more elegant way to perform this task? Or can anybody help me with starting an activity from an object method within a service? Thank you!
There are two situations to consider:
When your service need to notify user your activities are not active, because some other app is active. In this case you should notify user via a system-preferred way: Android Notifications. You should not forcefully show dialogs or activities if user is using some other app. That's what notifications are for.
If one of your activities is active (no matter which) then your service should send a broadcast and interested activities should listen for it and act upon it. That way your service will not depend upon specific activity and will not need to keep track which activities are active at the moment the notification must be shown.
You can make your object Parcelable and add it to the Intent that will start the Activity.
Or you can put it in a subclass of Application because that instance is shared between your activities and your services (as long as they're in the same process)
You might need the "START_NEW_TASK" flag on the Intent
Related
Lets say I have an activity that has a data object. It updates its gui component based on that object. Now lets say that it is paused ( OnPause is called) but not stopped or destoryed
Meanwhile , a push notification is received ( intentservice is started) and I need to update that object with the push notification object so I gui is updated when the app is resumed.
I thought about sending a broadcast to the activity so it can update its dataobject But I read somewhere that when activity is paused then broadcasts are not received.
What should I do in this case?
The hard but correct way to do this is to build your own custom ContentProvider for your app and update all data received from web services and push notifications to this ContentProvider. When the Activity comes back into the foreground, it updates itself with the new data provided by the ContentProvider.
It is hard because making a custom ContentProvider is a lot of work. It is the correct way because it is in conformance with the behavior of mobile applications and with the Android architecture: say a user activates a web-service or some computation-intensive task, and then dismisses the app; or say a push notification arrives and requires the app's data to be updated and displayed. In both cases, the app's Activitys may no longer be in the foreground, but a Service can be used to perform some non-UI operation. Now at the end of that operation, the Service makes changes to the data through the ContentProvider, and when the user activates the app again, the Activitys get their new data from the ContentProvider.
To quote the official tutorial:
Content providers are the standard interface that connects data in one
process with code running in another process.
As a developer, you should always assume that the user may invoke an app at any time and dismiss it at any time. Irrespective of whether an Activity is in the foreground or not, the app's data needs to be correctly updated and maintained.
Google's own apps use custom ContentProviders. The Gmail app in particular makes use of its ContentProvider to get new emails when network connectivity is available and display emails offline. The Facebook, WhatsApp & Twitter Android apps also make use of ContentProviders.
You pretty much treat it as if the Activity was destroyed. You can't really assume that it won't happen once onPause is called.
If the object represents something that's persistent, then simply update the persistent portion of the object and retrieve it when the Activity resumes. If it represents a state of a Service for example, then bind to the service and update. If it's a database, then update the database then refresh the Activity onResume.
If it's a temporary object that's only valid through the life of an Activity, then you need to make something persistent that the Activity can check when it resumes. Something simple like a boolean variable in the "sharepreferences". In onResume, check for the object, if it exists, then retrieve object, then clear the object.
I thought about sending a broadcast to the activity so it can update
its dataobject But I read somewhere that when activity is paused then
broadcasts are not received.
What should I do in this case?
I think the resource of that information is incorrect, if you declare a receiver in onCreate and remove it at onDestroy you wont have any problems. What I mean is, first parse the push notification with your service and then send localBroadcast to the activity. It is as simple as you thought. then update your GUI at onRecieve method of your reciever.
You should bind to the Service when the Activity starts. Then in onResume you can request updates that may have occurred while the activity was paused.
You may consider passing data to the activity through a callback to update variables in the activity while it is paused, but then you will need to update the UI in onResume.
Also consider that when your Activity is paused, it may get destroyed and re-created. You don't seem concerned with that scenario based on your question, but I thought it important to explain it. to handle any changes for this scenario, you would need to persist the data for the change. If you are persisting the data, then you don't need to bind to the Service you simply need to check the persistent data store in onResume.
EDIT:
In your comment you mention an IntentService which you cannot "bind" to. You have several options in this case (basically listed in order of preference). First, you can create a Service when your activity is created, then have the IntentService forward intents to that service. Second, you can have a Static variable in your Activity to allow the IntentService to access a shared data store. As mentioned previously, you can also persist the data (put in SharedPreferences, a file or a database. Last, you can use the Application class to store references to the data so that while your app is active, you can pass data.
So basically what i am trying to do is i want a service that runs in background and updates the LatLong to the server. This operation needs to happen all the time even if the application is running or not.
Now when the application is launched i want the service to calculate the distance between the latlong and update the UI in addition to the work that it was already doing i.e. updating the latlong to the server. i want the service to do the additional work for multiple activities. lets say i launch the application and i am on Activity A, onclick of a button on Activity A the service starts updating the UI and when we click gain it stops updating. Now i am on Activity B and on click i want the service to do some work in addition to the updation of LatLong and update the UI.
What would be the best approach to achieve this.??
EDIT
The problem i am facing is not getting the service update the UI but making the activity communicate with the service when it has already started.
i can pass on some data when i am starting the service but how to communicate with the service when it has already started. How to tell the service that see you are already running and doing some operations now you have to perform some more operation on top of the previous operation.
I can make some static method in the service and call them when i need to perform the extra operation but i dont wanna do that.. i want to better approach.
Here is the basically services runs on the same main thread process as ui. When you want make it run continuously you have run it in your tread. In this way you avoid service being get stopped as application go in background or killed. (Please take look at Service.START_STICKY flag, this is what you need as i guess).
And more coming your second problem of activity getting updated with service information or data that is being collected for this you need look at " How Bind the service". (In activity check for service connection and Binding to a activity, Unbindibg is also there have look at it also). Activity has all the call backs for it you need to implement binder.
EDIT
Service to update ui has to have send and receive intent mechanism. You can broadcast and intent from the services check your activity is running or not. If running broadcast intent and have receiver in activity to listen it.
You can do it by interface mechanism too
I'm building an app that registers a Broadcast Receiver for Connectivity Changes. When connectivity is available, the app performs a GET request and display the data in a ListView.
I registered the Broadcast Reciver (Connetivity Changes) and it works as expected. But I have a huge dilemma. I want to notify the MainActivity when Connectivity is available.
My first approach was using a class that extends from Observable and implement the Observer interface in the MainACtivity. I stopped that solution because I started using static variables and static methods. My other solution was using a Custom Broadcast registered in the , the idea is sent a broadcast from the Broadcast Receiver and catch it in the MainActivity.
I read several suggestions and a can't get a recommended solution. What is the best approach to this situation?
Do you need to notify the Activity only if it's currently running? Or the next time it's run?
For the first case, you can create a second BroadcastReceiver in the activity, register/unregister it in onResume()/onPause(), then notify it via an intent sent from the Service (all this using a LocalBroadcastManager). However, is that was your intent (heh) then you might as well have a second receiver in the activity for the original broadcast, so I guess it's not likely.
The other way (notify the Activity the next time it's accessed) is even simpler, just use SharedPreferences to record a boolean flag indicating that the task is pending. When the activity is resumed, check for this flag, do the needed work (make sure the connection is still available) and then clear it.
A third possible scenario (which I would think more probable, even though it doesn't match your description of the problem) is that you want to download and store the data at the moment the connection becomes available, then just have the activity load it when it starts. In this case the service would perform the download, then either notify or use the flag trick so that the activity knows new data is available.
Depending on the scenario, you might also want to take a look at Sync Adapters.
I am implementing a Service which will start when MainActivity starts. This service checks for and maintains a network connection.
I have not bound the Service to the Activity because I want the service to continue running even if the activity isn't available. The Service will receive messages from the server that it is connected to.
I am struggling to choose the best logic to do the following when the service receives a message.
Check if MainActivity is currently open and in front of the user
If it is call some methods in the activity to interact with the UI
If there is no activity update the notification are.
My question is;
How do I correctly check if the activity is running in the UI from my service? I know that I could bind the service but I wouldn't want to unbind it if the activity is closed. Would that be a problem?
I will somehow need to send messages from the service to the activity. Given the above scenario what would be the best way to do this?
Do it differently.
If your Service does not run in a separate process from your Activities, then your Service can provide a synchronized (multithread-safe) list of messages via a subcalssed Application object, where your Activity can look it up. However, this would only be best if the polling occurs on certain other events.
If you want to sort of "push" the message to your Activity, your Activity should register with your service upon finding out that it runs, not the other way round. In this scenario, your Activity should implement an interface through which the Service can notify your Activity of new messages in a Thread-safe way.
Of course you could also go straightforward and simply post notifications which open an Activity, but as I understood it, you want to provide a more smooth integration.
An idea would be to let your Service send status bar notifications when a new update is available.
Implement the notification such that when clicked, to open MainActivity.
Then, when the user will click on the notification, if the MainActivity is already running then it will be brought to front, otherwise it will be started.
So this basically eliminates the need to check if MainActivity is currently open in front of the user (which I see as a bad practice).
I have the following framework for my application:
1. a Network thread that runs in the background (a queue) for issuing request and get async responses. The thread is started and stopped in the Application Object so it's leaving through out the whole application.
2. a DataManager which is also a member of Application and has different DataManagers for the data types i retrieve from the network. the data manager itself is the listener for the responses from the network so it's safe until the application itself dies.
3. this is the problematic part. Some of my Adapters and part of my Activities are DataListeners for my DataManagers, that means that the data manager keeps a reference to them.
When a phone call or some other phone event occurs i've noticed that the activity is usually in paused and not destroyed and so receives my events, which is ok. the problem starts when landscape\portrait is changed. since i keep a referenced to the activity in an Application bound object, the activity can't be destroyed on one hand, BUT the event is still getting to the listener, only the wrong one...
Basically i can fix that issue by removing the listener in onDestroy and retaining configuration boolean to tell me that request was allready issues and i just need to put a listener and try to retrieve the data from the data manager.
However :-) i was wondering how android handles this cases usually, if for example this was a Service running. or if the Service is a local Service that used Bound and passed on the Activity as a Listener to the network Event, the same things happen, untill the listener is not removed the Activity is leaked and lives on, but without it, no way to get callbacks from the network...
an Intent requires serilaztion and deserilazation of data which can be heavy (Bitmaps for example?)
And anywa, asuming i send an intent on each respose i get, how do i get the intent to the Activity (i know of getIntent, but if i get another one , not related, do i get it as an 'event' ?)
From what I gather it's customary on Android to remove yourself from listener lists when the activity is destroyed. It's kinda error-prone, but I think it's the generally accepted way to do it.
You could imagine your service accepts only one listener, which may or may not fit your case, and when the activity restarts its registering with the DataManager would overwrite the old activity which would in turn be garbage collected. The drawback is, you don't free the activity memory if it is destroyed but the service lives on, so it's probably better to just remove the activity from listeners.
Android development is rather different from other platforms (e.g. BlackBerry). I'm not able to give you a quick silver bullet solution, however here are my thoughts on this:
Some of my Adapters and part of my
Activities are DataListeners for my
DataManagers, that means that the data
manager keeps a reference to them.
OS kills Activities according to their lifecycle. So you should avoid keeping a handle to an Activity in another object which is supposed to live after the Activity is destroyed by OS. Otherwise you'll get memory leak.
Also keep in mind Application sublass instance does not always live for the whole application session (a session from a user perspective). If your app goes in the background, for example, due to an incoming phone call, then your entire process can be killed. See details here. As soon as you Application sublass contains some state which is not persisted if process is killed you may mistakenly expect your handles to point to some non-null entities. However after going to foreground (and process restore) those may just be nulls because a new instance of Application sublass has been created by OS.
Ok, so let me describe the problem and the solution i found in more details.
The problem:
I have a Service\Network Thread that needs to notify Activities that sent requests through it that either request or Error has arrived in an Async way. Using Listener Pattern requires me to set listener before or when i send a request like so:
mNetService.setRequest(request, this);
where this is Activity that implements my listener Interface.
But doing it this way requires me to remove the listener from the service in onDestroy and returning the listener, if i ever sent a request back in onCreate\onResume, but the response can also arrive exactly when the activity is not listening (landscape\portrait event) which requires me to keep the Error\Response in the service until some1 picks it up and resets it.
The solution i found:
using Broadcasts and BroadcastReciever.
this is only part of the solution but it let you have a listener to broadcasts (that can be specific for a certain class type meaning Activity) and action.
Since all of my Activities inherit a base Activity class i've made they all have a BroadcaseReciever inner class that listens on certain action in it's filter.
is i enable the listening in the C'tor of my Activity the listener will be registered in onResume and deregister in onPause.
If the listener gets onRecieved event it will call a method in the Activity (which i can override in my specific activty) and pass it the Intent i got which can contain all the data from the response.
The only missing part is what happens if the Activity dies for a second and only then the broadcast arrives ? ah, that's a problem, so android intorduces Sticky Broadcasts that stays there untill you remove them with removeStickyBroadcast(Intent), so when is ent broadcast from my service i send Sticky broadcast, when the Activity gets my Broadcast it removes it so it wont stay around and mislead the activity about new response that arrived.
The only problem with it is if i send a request, don't wait for the response and goes to the next Activity right away, in this case when i'll go back to that Activity it will think it got the response. Didn't find a proper solution to that just yet. But it's better then my previous solution.