Calling a lengthy Service method from an Activity - Best Practice - android

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.

Related

Long running tasks with callbacks to activity or fragment

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".

How do I use the Service feature in Android

I am new to android development and having trouble understanding how I should use service's and more specifically which kind. I am developing an simple system that only will do to things. One of those to is to continuously ask a server simple telnet questions. The answer to these questions should be prompted on the screen.
So to simplify my question. What kind of service should I prefer? bound, intent service etc?
I presume it has to run a own thread since it is suppose to do network comm, so how should I do that.
Finally and most importantly, how do I supply/give the MainActivity the information the service has gathered and post it on the screen?
What kind of service should I prefere? bound, intentservice etc?
A bound service runs only as long as another application component is bound to it. With other words, if an activity bounds to that service, and later that activity gets finished, the service also gets destroyed.
So, first decide the behaviour of the service you want to have. Do you want it to be destroyed when the activity bound to it gets destroyed? If yes, then perhaps a bound service is the right thing to do, if not then use a started service instead which can run in the background indefinitely, even if the component that started it is destroyed.
I presume it has to run a own thread since it is suppose to do network
comm, so how should I do that.
Yes, you are right. You can use the Service class and create a thread inside it that will do the heavy work, or, you could simplify things by using an IntentService which provides its own worker thread.
Finally and most importantly, how do I supply/give the MainActivity
the information the service has gathered?
If you decide to go with a bound Service, then you'll be able to communicate with the service through a so called binder object. On the other hand if you go with IntentService then you could use a ResultReceiver, or a BroadcastReceiver to send the result back.
Suggested readings:
http://developer.android.com/guide/components/services.html
http://developer.android.com/guide/components/bound-services.html
Here is a quick summary on services in Android, hopefully this will help in deciding what approach to go. Reading Android Services is highly recommended
Android Service
"A Service is an application component that can perform long-running
operations in the background and does not provide a user interface"
runs on the main (UI) application thread.
it is given preference over activities in termination when resources
are low
it is not intended to interact directly with an activity/fragment (an activity may be destroyed at any time) no simple callback ability due to above... however there are some ways to address this using Intents, Handlers and Messages
an activity can be bound to a service which
basically gives an instance of the service to call methods, the methods will run on the main thread, a suggested way to use a separate thread, is to use Executors

Service to Activity sticky communication

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.

Does this Activity - Service messaging pattern cause a memory leak?

I have a Worker Service, and a bunch of Activities. Every Activity has a Handler. The Activites can start jobs by sending Intents to the Service with the startService method. These jobs get into a queue, and are processed sequentially.
To report back the results of the finished jobs, I supply the proper Activity's Handler wrapped in a Messenger object with the Intent that describes the job. The Service sends back some message for the calling Activity through this. This works just fine.
But the supplied Handlers seems to remain in memory, even after the corresponding Activites got destroyed, continuing to handle the completion messages.
How can this be? Shouldn't the handlers be destroyed with the Activity they're part of?
Does this cause a memory leak?
Since the Service has a reference to the Itnents which still have a reference to the Activities Handler then the Handler isn't going to become available for Garbage Collection.
Have you seen this video from Google IO? It's about building apps that use RESTful web services so isn't directly relevant but the approach of delegating the responsibility for responding to long running events will partially map to your problem.
If you don't want to change things around too much then you need a way in your Activities onClose or onDestroy to notify the Service (and through it the Intent) that the long running task it is in charge of isn't needed anymore. It removes it's reference to the Handler and so the GC can get rid of it.
That or centralise the management (as in the video) of running tasks and responding to their lifecycle in a ServiceHelper class. That class can publish events as things happen and the activities can listen for those events.
This has the benefit of your code being in one place so you don't have to change every activity when you want to change how you handle the service.

android : communication between service running in background and activity

I have a service running in the background. Based on some condition it has to start some activity. Activity has to send back the response.
I did google search and found out we have to use Notification mechanism. But I am not clear how to send the response back from activity to the service running.
Also service is collecting sensor data(acclerometer, gps). So should activity be started in separate thread so that collecting sensor data is not affected.
Please clarify.
Activity would be started in main UI thread, instead, your long-running service should run in and manage its own thread, since according to the document, service is also created in main thread.
Basically the best way to communicate is to use Intent. This allows loose couple of sender/receiver (i.e., activity/service in your case). Intent is a large topic in terms of android, and yet it is one of the most fundamental one, I think you should look for tutorials online about it.
If your activity is opened and return the result after completing the task of Activity then you can use startActivityForResult and then return the result.
Using of notification is simple, just create a interface class, and implement the class in your service. When you need to send data back to service, you can just call the appropriate method with data.

Categories

Resources