Am having an activity that will start service, service will download something from internet and i have to update activity UI.
but consider below cases
If my activity is alive i have to update activity UI without broadcast receiver, What is the best way to do this.?
If my activity is not alive and when it comes alive/foreground then i have to update UI with service result, How to do this.? (without saving into DB)
Let me drop my suggestions point by point,
Yes you can achieve it by EventBus (or) interface. Coming to eventbus, it is similar to broad cast receiver.
When the activity is not alive, you are fetching the data and when coming to alive you had to update the UI. In order to do that somehow you had to save the value somewhere either internally or externally (OR) you had to fetch the values from the internet whenever the activity comes to alive.
Related
Question: What is the best practice for reporting progress/complete from long running task to an Activity? And what to do when the progress/complete report happens while the Activity is in the background/orientation changes?
Real life example:
An Activity makes a network call getting data from a server (this could take 10+ sec).
When this network call is finished, the Activity should be notified and the Activity should show that the network call is finished.
This is easy to implement as long as the app stays open. My problem is, what to do if the network call is finished while the app is in the background (activity will miss any callbacks).
I have been looking at the following ways to do this, but I can not decide what to do:
Service that spawns a thread where the network call is executed. The Service is bound to the Activity. On network call finish, Service callbacks to the Activity. If Activity is in background when the Service makes a callback (therefore the Activity misses the callback), should the Activity poll the Service for saved data?
IntentService that broadcasts the data when network call is finished (what to do if Activity misses this broadcast because it is in background?)
AsyncTask, but this is bad when Activity is in background etc.
How should I approach this problem?
I've solved this problem using HeadlessFragments as its called. This blog post explains in detail how to implement it and the concerns you mentioned are handled by it.
EDIT:
For the questions in the comment:
To your specific question, about callbacks being lost when Activity is in the background, the answer is no. Being in "background" means that Activity is still alive. From the link I posted, the callback, which is the Activity itself, is removed when its detached from the Activity i.e when the Activity is destroyed. So, if your Activity is in the background and not destroyed, it'll still get the callback and do whatever you do in that callback. Although Android can kill Activities that are paused, in which case, your Activity will be destroyed and you won't get the callback. In such case, you can either save the data you get from server in a persistent storage, like SQLite, and prevent making another network call or make the network call when the Activity is created which will ensure that whenever the Activity is created, you'll have data to display (given of course, the call goes through).
The use of Fragment was specifically to handle the configuration change you mentioned in your question. The running task is still being done by the AsyncTask and not by the Fragment. The Fragment only holds a reference to the object. So, I'd argue about it not being a "best practise".
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.
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 a service that downloads some data from internet and periodically sends progress to the indicator activity. In the end of processing service sends a result.
I have a question what is the best way to achieve persistence of the communication.
Messenger or ResultReceiver, I need to parcel them into Intent and store list of listeners in the service. But on configuration change activity destroys, and it's hard to maintain this list.
LocalBroadcastManager, I need to migrate from Messages to Intents, and also there is no sticky send in this class. So if I get result while my progress activity is in background result will be lost.
BroadcastManager is good, but I don't need to broadcast my progress system wide, and security issues.
Any ideas?
You may want to give Otto (http://square.github.io/otto/) a try.
In your service, whenever you want to communicate with the activity, post a new event using a shared Bus. You should do that on main thread with a handler or main looper since you are probably using IntentService. The service may act as a producer as well. When your activity is recreated, current known value will be posted.
Your activity just needs to register with the Bus and subscribes to the right event. When it is paused, just unregister with the Bus.
I belive the best way to achieve that persistance is:
After the service downloads, you should save your data in a database or a file.
The service then sends broadcast to update.
If the activity is "alive" all goes well and it goes to the database/file to get the updated content.
If the activity was killed or something, you just have to make sure the data is in the database/file so that when you start/restart the activity you can get the latest content from database/file.
While downloading keep a state and progress saved in the db/file the same way.
Check this Google I/O Session, it explains this really good.
Use static variables inside your Application class (extends Application). Inside Service you set this variables. Inside Activity you read periodically this variables.
You should use massenger to send download progress, because it is more secure and less expensive method then broadcast receiver.
I'm developing an app with a service that forwards calls to a web-service, and a few activities that place those calls. The activities need to process the results of those calls. For example, I have a writeComment method on the service, that accesses the web-service and returns some information about the newly written comment.
Right now I let the Activity take care of all the threading. The Activity binds the service, and then uses an AsyncTask that calls the bound service's writeComment method.
All works well as long as the Activity isn't stopped while the AsyncTask is running. If it does (easily happens when flipping the phone), the AsyncTask dies a violent death when trying to update the UI in onPostExecute. I'm not entirely sure how to fix this - I do need to let the user know the server has been updated.
If I go the other way around, and register a callback with the Service, I'm still a bit stump, because I need to notify the Service the Activity has changed - I need to tell it not to notify me in the first Activity's onDestory, and reregister in the second Activity's onCreate. And I need to handle the case where the asynchronous task completes after onDestroy and before onCreate.
What is considered Best Practice in this case?
Thanks,
Itay.
My intuition tells me to let the service handle the threading. Services are far less transient (although still transient to some degree) than activities and therefore you'll have less issues of threads trying to interact with a Context (be it an Activity or a Service) that's no longer there. Have you looked at the IntentService class? It handles a lot of the threading for you.
In my app, I have a long-running service and Activities that need to render data in the service. The service also pings the Activities when there is a change but the Activity can also query the service. The way I approached this was two-fold.
Firstly, I bind my activity to the Service in order to send messages from Activity to service.
Secondly, the Service sends notifications with Broadcasts and the Activity listens for those broadcasts. I set that up in the Activity onResume and tear it down in the onPause. I think this is the part that you're missing.