Pattern for reusing Android AsnycTask over several Activities? - android

I have several Activity subclasses in my project, each calling a SOAP based web service, processing and displaying the results. The SOAP serialization, the call handling and the parsing of result into various POJO objects is encapsulated in the MyWebService class. This class executes the actual web service call(s) via an AsyncTask.
For being able to pass back the results to the calling Activity subclass, I figured I enforce that all these activities should implement a WebServiceResultProcessor interface, defining a single function (processWebServiceResults) acting as a callback for the AsyncTask, called from onPostExecute.
I also want to display a ProgressDialog during the web service call. And here comes my question. For being able to display the ProgressDialog (either from MyWebService or it's AsyncTask), I need to pass a reference to the caller Activity's Context. And for being able to execute the callback function from the AsyncTask, I also need to pass the same object reference, but this time as a WebServiceResultProcessor. This seems to me a code smell, passing the same object twice, but can't see any way around that. Instead of interfacing, I could create a new base class, extending the Activity class and enforce inheritance from the extension class, but that would mean I'd exclude ListActivity and the likes from using this MyWebService class.
Is there a better way to do this?

+1, a nice question!
This is not a direct answer on your question. However let me say I think AsyncTask is not a right choice for such stuff. I think so because in this case AsyncTask holds a reference to an Activity (via ProgressDialog instance or the callbacks to be called from onPostExecute()).
Just imagine: in Android the OS may kill the Activity before AsyncTask executes its doInBackground(). This is, of course, some sort of a corner case, but it isn't impossible. Consider a scenario: user gets an incoming call, your activity becomes invisible, the OS needs some more RAM and thus it decides to kill your activity. A memory leak case, at least.
I don't know why Google literally hides the info on how UI should be properly separated from background tasks. Yes, they say "use a Service". But it is not a trivial undertaking. It's a pity Google provides nice guides to almost every development topic, but not on this one. Nevertheless I can suggest to check the "Google I/O 2010 - Android REST client applications" presentation for inspiration. Looks like they gave a key on how such things should be done in Android.

You may have a look into this blog article (part 1 and part 2), which implements a web service with AsyncTaskLoader and the same web service with a Service component. Furthermore it shows the differences between both approaches and there are also interesting comments to the article.

Despite Arhimed's warning, I ended up using AsyncTask, as it still fits my purposes. I just make sure that all Activities calling web services, upon their onDestroy(), send a cancel() to the invoked AsyncTask. The AsyncTask implementation itself gracefully handles the cancel request by checking isCancelled() everywhere where necessary.
As for the original question, I must have had a lapse - the solution is really simple. I pass the Activity subclass instance as an Object to the AsyncTask, and cast it to either Context or to WebServiceResultProcessor, as necessary. Fragments showing how it works:
if (callerActivity instanceof Context) {
ProgressDialog dialog = new ProgressDialog((Context)callerActivity);
}
...
if (callerActivity instanceof WebServiceResultProcessor) {
((WebServiceResultProcessor)callerActivity).processWebServiceResults(soapObject);
}

Related

Using context in an AsyncTask via a Fragment that has no UI

I have previously had my App working with just activities and am now working on converting to fragments in order to improve the UI.
Previously my Activity started an AsyncTask and passed in itself to be used as the Context when certain methods required it (not UI operations, but calls to shared preferences and content providers). I have now learnt that this approach can lead to undesirable outcomes if the Activity is destroyed and garbage collected, but it did compile and run fine.
I began this change because I wanted to make my loading screen behave better when the app was paused and stopped. I realised people frown on loading screens in Android but for me it is required as I have an operation that will take 20 seconds or so and that needs to be completed before the app will function.
So using this guide, I began improving my app.
In short the guide moves the AsyncTask into a Fragment that does not have an attached UI, with a separate Fragment for displaying the loading screen with ProgressBar. This means that the Fragment that spawns the AsyncTask does not have a Context, meaning I cant pass one in to the AsyncTask.
As I said before I have operations in the AsyncTask that require a Context object, so where can I get it from? Should I just pass in that data to the AsyncTask before I start?
As far as I know, the context is not a static property, so you actually need one object to retrieve it.
Thus, you can either go the "hack-way" as in this post:
Static way to get 'Context' on Android?
or you can follow Android guidelines and use a Service for your background loading. Remember that AsyncTask is an utility class designed to help in background operations that later need to communicate with the UI, so you should use AsyncTask in correlation with a UI object.
If you, instead use a Service, then you got no problem, since the Service object itself is the context that you need.
If your AsyncTask is not handling any UI components you can use the parent Activity's context. So where you previously passed in this you'll now pass in getActivity(). Note, if you do have it changing the ui this will set you up for Null Pointer Exceptions.

Making Asynchronous Service Calls in Android

I am trying to make asynchronous service-call in my android app using AsyncTask Class, but for each and every service call in my activity i need to have a subclass in my Application which Extends AsyncTask. Can anyone Suggest me a better way of doing this???
In My Scenario Service Calls have different return-type,then i need to return an object for all service calls and typecast it according, Is there any better way of doing this ???
Is it a service you wrote? If so, you could make the service itself asynchronous so that you can make calls on it that return instantaneously and later get notified via a callback. That would remove the need for the AsyncTasks on your Activity.
If you can't change the Service, one thing you can do is have a background worker thread that's responsible for interacting with the Service, and you post messages to it from the main thread using a Handler. The worker thread uses another Handler to deliver the results back to the UI thread once each work item is finished.
See: http://developer.android.com/reference/android/os/Handler.html
"AsyncTask must be subclassed to be used." sez the droid.
Don't declare the AsyncTask as an inner class of your activity. Declare this class once in it's own scope, and you can use it from anywhere. As far as the data to pass in and out, you can make the first parameter a String or Uri and pass in the request data, and you can use an internal listener object in the AsyncTask that can be set by the activity to receive a call back when onPostExecute fires.
EDIT
I made a gist to demonstrate the simplest version of this. Using the example AsyncTask-derived class, you can reuse this one class throughout your entire app and pass it all of your endpoints and receive the result inside your activities (or anywhere else you need to make your service calls). If you need to make this more extensive, you can just change the input object from a String to some more complex data structure containing anything you need to pass to your service call (post params, http method, etc) and you can change the signature of the OnPostExecuteListener interface if you want to return structured data and not just the raw result
https://gist.github.com/80c59fb70e195ca142bb

Android AsyncTask inside AsyncTask

So, I'm working on a barcode decoder, which once we have the barcode goes to multiples API over the internet to decode what was just scanned.
The thing is that I have to link some XML parsing together, and I don't know if I'm doing it right.
So, once the barcode is scanned, my program calls an ASyncTask which goes over an API to retrieve the product name. Once it has the name, I want it to call another ASyncTask. I know this is possible by instantiating an ASyncTaks in the onPostExecute() of the other but, I think this is wrong, because it's like boxes within boxes.
So isn't it possible/better to instantiate my second ASyncTask inside my main Activity, and make it wait until my first ASyncTask is finished ?
(english isn't my primary language, I hope I made myself clear).
I think it's absolutely legitimate to start the second AsyncTask in the onPostExecute of the first AsyncTask, Mixing both operations is a bad logical idea, As "The Offspring" said - "You've gotta keep 'em separated"
If you don't want it to be directly inside the onPostExecute itself, set a handler to execute it in the activity and call this handler from onPostExecute.
And last thing - If you have a lot of logic - move it to a separate file, don't keep it all at the same file.
In situations like this it might be better to batch long running operations together in one AsyncTask.
Another option is to use the Loaders API, this makes chaining tasks much easier http://developer.android.com/guide/topics/fundamentals/loaders.html
You can go for another approach if you are facing often a situation like this. That is to merge requests and operations inside of runnables/callables and to manage them separately within say a queue for instance.
Here is a nice approach.
http://ugiagonzalez.com/2012/07/02/theres-life-after-asynctasks-in-android/

How to extend an existing background thread solution?

I am using Eclipse to develop an Android application that plots Bluetooth data.
I am using open source code, which has an existing solution that I want to extend and not replace to solve my development problem as stated above.
The open source code has a very nice and solid background thread that among other things continually logs BluetoothData to logcat even when I switch to a new activity.
Currently I have a solution which I am concerned about: I simply leverage a background thread method that writes to logcat to call a static plotData() method in my Plotting Activity. The result seems good. I get a nice plot. It clips along in real-time. Looks like an oscilloscope.
But I have received negative feedback about using the existing background thread coupled with a static method to plot the BluetoothDate. It has been suggested that I use a new thread, or add a handler, or use Async Task, or AIDL to solve my problem.
I have looked at all these solutions without success. Nothing seems to work like my static plotData() method. That is to say the existing background thread calls my static plotData() method which results in a real-time plot that looks great.
But I am still concerned about the negative feedback. I simply want to extend my existing background thread solution which I have done by having it call a static method to plot the data.
What are the problems I might face with this approach? Thread safety? Deadlock? I don't know.
Why do people keep suggesting that I create a new thread, handler, Async Task, or Service to solve my problem when extending my existing thread to call a static method seems to work just fine?
Any suggestions? What are the problems with extending the existing thread to use a static method to plot the data in real-time?
Anyone who says that you should use AIDL for this is a loon who should not be listened to. :) Also someone saying you need a Service if you don't want to have your background thread running when the user is not viewing your activity.
I'm not sure what you mean by "writes to logcat to call a static plotData()." You should write to logcat only for testing. Writing to logcat doesn't cause a call to any Java method.
If you are calling a static plotData() method on your Activity, you need to be extremely careful with this: first because it is difficult to figure out what activity instance should be called from there (it may go away at any time from the user finishing it, or be recreated as a new instance when the configuration changes, etc); and second because you can't touch your app's UI/view hierarchy from a background thread without risking that you corrupt its state (since the view hierarchy is single threaded).
The general model one does for this kind of thing is to have a background thread doing some work, generating the next data to display. Once it is done with the work you send a message to the main thread to have it display the new data. AsyncTask can be a simple way to do this, it takes care of the underlying message sending and threading. You can also implement this yourself, at some point having a Handler that you post a Runnable on or send a Message to that once executed on the UI thread will update your view state.
(Of course if you are using a SurfaceView, the whole point of that is to allow drawing to it outside of the main UI loop, so your background thread could just draw directly on to it as needed. Basically that is like writing a game.)

Activity with backgroundthread, not innerclass, communication

Hey all, this will contain a few questions since I don't seem to really get it.
I have 1 class, the activity. which should display informations.
Then I have a background thread, extends runnable, which keeps getting new data (there for I didn't use AsyncTask, I could use it as a service, but since I hold a some critical resources in it, I would like not have it released when exiting the activity thread)
But I am in great doubt how to communicate between these 2.
First I thought of Intent, but these seem to be used mostly for launching other activities, or alike, and I need something permanent, since data will be in a steady flow.
Then I found out handler, but this doesn't seem to work when my thread is not an innerclass, so I'm thinking about either going back to the old Java observer pattern, if it's not possible to somehow pass the handler to the outerclass.
Any thoughts would be greatly appreciated
Sincerely
Anders Metnik
There is a mechanism for your case - it is called handlers. Read more here.
As for having thread as inner class:
Create your thread as a separate class, add a constructor with a handler parameter and pass it from your activity.
Thread is not suppose to live outside Creator Activity Context, especially you want to preserve it out of Activity, better use Service (and manage the thread) to hold those data.
Intent is the best in terms of communicating between contexts. I think one of the scenario you can adopt is like this:
Application-class: holds those 'permanent' data you mentioned
Service-class: Work (background) and send out "intents" to signal the update state of the operations
Activity-class: Intent Receiver. Whenever intent signal received, grab the necessary data from the Application-class.

Categories

Resources