I'm using a simple AsyncTask to download the sourcecode of a web page as a String. So far everything works fine.
However, I don't want to always do the same thing with the result String, sometimes I want to fill the gui with it, sometimes I want to parse it, sometimes I want to call more functions with it as a parameter.
Actually, I have more than one activity and more than one class that need to download the sourcecode of a page.
Of course, onPostExecute() is what has to handle the result of my Task, but since it will be called from so many places and for so many different reasons I'm really at a loss.
What can I do?
I really don't want to write 20 AsyncTasks that always do the same thing in their doInBackground(...) with different onPostExecute, nor I want the code from 20 different classes/activity to end up in a single onPostExecute, my code would be so complicated to maintain.
Any suggestion?
Thanks
I would resolve it with the use of interfaces. Make an async task that does the right stuff in the doInBackground and that takes some parameter so that you know what to do in the onPostExecute and pass the parameter and result down to onPostExecute.
then make an interface with a method like handleSourceCodeString(String source); and then implement one class for every action that you want to do. Then put the classes in a map in some init function.
Map<String, Class> myActionMap = new HashMap<String,Class>;
myActionMap.put("parse-soruce", ParseSource.class) //(where ParseSource.class implements your interface)
and then in your postExecute do something like:
((MyActionInterface)myActionMap.get(action).newInstance()).handleSourceCodeString(source);
I found this... love the idea... seems pretty straight forward and better than using interfaces in my opinion.
AsyncTask onPostExecute call from outside the AsyncTask
Look at the first answer
Related
I want to perform multiple tasks in Android. I know I can use AsyncTask for this. But my requirement is I want to execute second task only completion of first task. Then will execute the third task only after completion of second task. How it could be possible.
For this I am thinking to use multiple AsyncTasks i mean inside doInBackground of first AsynTask I want to start second AsyncTask. Similarly inside doInBackground of secondAsynTask I want to start third AsyncTask and so on.... Is it ok if I implement like this with out any performance issue or is there any other way of doing this. Please share your thoughts on this.
Create multiple AsyncTasks and call them in a chain.
E.g.:
Call the first task:
new FirstTask().execute();
Then FirstTask class overrides onPostExecute where it calls the second class:
new SecondTask().execute()
and so on.
If you don't want to reinvent the wheel you could use concat () operator of rxjava.
https://github.com/ReactiveX/RxJava/wiki/Mathematical-and-Aggregate-Operators#concat
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);
}
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/
I need some suggestion on how to go about this specific android problem:
activity A passes an intent to activity B,
B reads it, makes an API call,
B receives response, parses it, and updates its views from the response
now it works fine except fr a 2 second black screen during transition from A to B
is asynctask a solution? becoz the parsing data is not much and also is there a way to update UI views frm asynctask
To echo what Lalit said, an AsyncTask will help in this case. The problem that you're having is that doing the API call during onCreate is blocking the activity from updating the UI. If you use an AsyncTask, it will allow the activity to continue rendering the view.
As you're parsing the result, you can update the UI by calling Activity.runOnUiThread() or by putting the UI code in onPostExecute.
I'm not sure if AsyncTask is the best solution for your case.
An AsyncTask is very helpful if you need to do something in background and allow the user to do something else in the mean time.
I'd sugest to just use a Thread and define a progressDialog.
If you do it this way, your user will see the loading dialog with the spinning circe and not the black screen that looks more like if the App is freezing.
Let me know if you need help with some code samples.
Marco :)
Consider this: I've got Activity, in onCreate() I start AsyncTask to load its content. I've followed this sample. Now my problem is: I want to download file in that Activity, using AsyncTask. But I don't know how to make existing AsyncTask do various tasks.
If anyone had the same problem, I would appreciate your help.
Well, I've succeeded to make it call again and again... you have to instantiate your class as a null first (int the Activity).
MyAsyncTask asyncTask = null;
and then put it in a try... catch block:
asyncTask = (MyAsyncTask) new MyAsyncTask().execute(params);
The other thing you're interrested about is the differenc methods you want to run... Well, I wanted to do the same, but I've had no time writing that one, but I've thought about it on the way home from work.
I think your class extending AsyncTask should look like this:
class MyAsyncTask extends AsyncTask<Object, Object, Object> { }
create some variables or ArrayLists in your AsyncTask, and do the decision on the overriden onPreExecute() method where you have to make a switch, or some if's. Do the call/work on the overriden doInBackground(), get the result, and process it in the overriden onPostExecute() method.
I don't know if this line works, since I've had no time to experiment it, I really just thought about it, how to... :)
But I hope the thought helps at least! :)
You must implement two separate AsyncTasks with different doInBackground methods or add file downloading to existing one.
Remember that (from documentation):
The task can be executed only once (an exception will be thrown if a second execution is attempted.)