Asyntask in android - android

I am using async task as below. But I need to be able to call a different function inside onPostExecute based on different activities I am using the class below. For example when an activity loads I will use the below class as it is but when user clicks on a listitem in the activity I want to use the same class below but the callback functon needs to be different? Is there a way to do this in android.
class PerformOPTask extends AsyncTask<Void, String, ServerOutput> {
// connector=new JSONConnector();
Connector connector;
String curUrl;
ServerOutput currentSO;
PerformOPTask(String url,ServerOutput serverOutput){
//connector = new UnitTestConnector();
connector = new JSONConnector();
curUrl=url;
currentSO=serverOutput;
}
#Override
protected ServerOutput doInBackground(Void... params) {
return connector.getData(URLUtils.getFormattedUrl(curUrl),currentSO);
}
#Override
protected void onPostExecute(ServerOutput output) {
displayData(output);
Toast.makeText(BaseFragmentActivity.this, "Done!", Toast.LENGTH_SHORT).show();
}
}

You can add an interface in the adapter which contains an onComplete method or something like that. You can then add the interface in your constructor of your AsyncTask. Like this:
public interface OnTaskCompleteListener {
void onComplete(ServerOuptput output);
}
In your onPostExecute() you can then just call the onComplete()

You can pass some Object to PerformOPTask(maybe Activity instance for example, or some enumaration, or boolean if there are 2 options) which will identify who uses this class and which function to call on onPostExecute().

Both answer are right, you need to inject a dependency for that. And personnaly I prefer to inject them inside the constructor of my own subclasses of AsyncTasks.
The advantages of the solution of #Maria Neumayer is that it will provide something more generic, more abstract and more extensible than using the solution of #narek.gevorgyan

Related

How to get multiple implementations of a single AsyncTask class in Android?

I am developing an Android application, where most of my activities are fetching content from a MySQL database separately, through an http request.
For this, I am required to add the AsyncTask class separately to each such activity.
Is there a possibility that I may use a common AsyncTask class for all such data fetching and create their objects separately in the activities and fetch data based on the parameters?
Of course, you can create separate class extending AsyncTask for making HTTP requests, which will take appropriate parameters and re-use it in many activities. You don't have to create nested private classes in each activity. You can use input parameters of AsyncTask in doInBackground(parameters) method. See documentation of AsyncTask at: http://developer.android.com/reference/android/os/AsyncTask.html
Below, you can see very simple example of using AsyncTask with some pseudo-code:
public class DownloadDataTask extends AsyncTask<String, Integer, String> {
protected String doInBackground(String address) {
// you should have method for performing HTTP request
// and return result - in this case as String
String result = performHttpRequest(address);
return result;
}
protected void onPostExecute(String result) {
// this method is executed after downloading result
// now, you can perform some action - e.g. display data in a TextView
myTextView.setText(result);
}
}
In this definition: AsyncTask<String, Integer, String> first parameter is type of input parameter (in this case address of the end-point), second parameter is type of progress value (we are not using it in this example), last parameter is type of output value (in our case, HTTP response as String).
When DownloadDataTask class is placed in a separate file, you can re-use it in many activities with the following call:
new DownloadDataTask().execute(address);
Of course, it's very basic example with some pseudo-code. I haven't initialized TextView and I haven't provided implementation of performHttpRequest() method. You should adjust it to your needs. You can also upgrade this solution and pass reference to a TextView or another widget in which your result will be displayed.
Nevertheless, consider using RxJava and RxAndroid instead of AsyncTask. It will make you app simpler and less error-prone. I do not recommend using AsyncTask, because we have many better solutions for Android right now. Regardless of this fact, you decide which solution will be used in your project.
You can achieve this in much the same way as you would with any other Class - create a separate class file that extends AsyncTask and create an object where it's required.
For more flexibility, you could declare the class abstract and use an unknown type parameter, so that you can adjust it as your requirements change.
public abstract class MyTask<T> extends AsyncTask<T, Void, Void>{
#Override
protected void onPreExecute() {
Log.i("Tag", "onPreExecute");
}
#Override
protected void onPostExecute(Void aVoid) {
Log.i("Tag", "onPostExecute");
}
}
And then, whenever you want to create an instance:
MyTask<String> mt = null; //Or URL etc.
//...
if (mt == null) {
mt = new MyTask() {
#Override
protected Void doInBackground(String... params) {
return null;
}
};
}
mt.execute(params);

Call different callback from AsyncTask onPostExecute()

I have implemented an internal AsyncTask for my class that does initial setup data query from server and stores into device cache. The setup data in split between 2 JSON files. The first JSON is read/cached and if certain conditions are on then second JSON file will be downloaded and stored into cache. I want to use same AsyncTask from both operations.
In doInBackground(), I perform JSON download operation independent of JSON type. But in onPostExecute() I want to call different callbacks depending if its 1st JSON file or second, since they require different handling. Is that possible?
EDIT: Pls note I do not want to use booleans, enum to decide which callback to call as in future I will have more files to process. From my calling class I want to set the callback and rest should happen automatically.
Below implementation should solve your problem:
private class MyCustomAsyncTask extends AsyncTask<Void, Void, Void>{
private boolean mShouldCallMethod1;
public MyCustomAsyncTask(boolean shouldCallMethod1){
mShouldCallMethod1 = shouldCallMethod1;
}
#Override
protected Void doInBackground(Void... params) {
//code goes here..
return null;
}
#Override
protected void onPostExecute(Void result) {
if(mShouldCallMethod1){
method1();
}else{
method2();
}
}
}
i.e have a customized AsyncTask as innerclass.
If you use the same interface which contains the two callbacks this is no problem. Simply declare an interface with 2 callback methods (json1, json2) and pass an instance of the interface to the AsyncTask.
In your onPostExecute() you can call the callback(s).
As android does not support setListner Methods for onPostExccute so there is two ways:
Extend AsychTask and imlement setOnPostExcuteListner
Or just call "your method" from onPostExcute simple!

Android AsyncTask with notification

I am currently starting to develop Android applications, and I must say that it all came out very very simple and straightforward.
I have a small question about the AsyncTask. Maybe I've been doing something wrong, but here's the situation.
I have a small app that needs to load a list's content from the web.
I developed everything based on fake requests, and it all came out awesome. Then I updated the code with actual requests and got the 'Network on main thread error'. So I decided to switch to AsyncTask.
I was wondering if I could let AsyncTask just do the asynchronous work, and handle the result somewhere else (where I actually have the GUI connections and everything). I thought that in terms of readability and logic it makes more sense to have all the code that handles the interface in the Activity, but how could I let the Activity know when a task was completed?
I wrote these simple classes and interfaces (and it works) but I wanted to know from you if this is a good thing or there are better methods to do that.
So, here's the code:
public interface AsyncDelegate {
public void executionFinished(LazyLoaderWithDelegate lazyLoaderWithDelegate);
}
This is a simple interface. The purpose is to have the Activity implement this and handle the 'executionFinished' method. Something like a listener.
import android.os.AsyncTask;
public class LazyLoaderWithDelegate<Params, Progress, Result> extends AsyncTask<Params, Progress, Result>{
AsyncDelegate delegate;
Result result;
public LazyLoaderWithDelegate(AsyncDelegate delegate){
this.delegate = delegate;
}
#Override
protected Result doInBackground(Object... params) {
//This will be Overridden again from the subclasses anyway.
return null;
}
#Override
protected void onPostExecute(Result r){
this.result = r;
delegate.executionFinished(this);
}
public Result getResult(){
return result;
}
}
This class basically gives a skeleton structure to notify the delegate when the task is finished.
That's all. Here's an example of using this classes:
public class LazyVideoLoader extends LazyLoaderWithDelegate<Void, Void, List<List<Video>>>{
public LazyVideoLoader(AsyncDelegate delegate) {
super(delegate);
}
#Override
protected List<Video> doInBackground(Void ...params) {
return ServerInterface.getVideos();
}
}
public class MainActivity extends Activity implements AsyncDelegate {
private LazyVideoLoader videoLoader;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
/*
* Set up the lazy loaders
*/
videoLoader = new LazyVideoLoader(this);
videoLoader.execute();
}
#Override
public void executionFinished(LazyLoaderWithDelegate task) {
if(task == videoLoader){
List<Video> result = videoLoader.getResult();
//Do whatever you need...
}
}
Everything you run on onPostExecute is in the UI Thread. Also you can run a code on UI Thread once a certain part of the work is done simply on onProgressUpdate by calling publishProgress on doInBackground.
Refer this for more information. It has everything you need to know about AsyncTask.
If I understand this correct you have a seperate class, which runs an AsyncTask. If the task is completed the as callback used interface informs the Activity. This is good if you think in components to make the code more modular.
The most common practice is to use an AsyncTask as an inner class in an Activity. If you just wanna download a picture or something similar with relative small size this is the prefered way. Because you can access all fields in your inner class, which makes things easier than passing them around in constructors/interfaces.
Don't use an AsyncTask in an extra Class just for readability. If you have to do some fair calculation/modification on the results with different methods your way is ok.

How to use Context to access/manipulate another class/activity

I want to create a generic AsynceTask class that all my activities use/share for downloading content from a url. for this reason, I don't want the OnPostExecute to do anything other than to send the content back to some method in the activity that invoked the AsyncTask class.
I know that I need to create a constructor that sets the context of the Activity that invoked the AsyncTask, but then what, how do I use the context to send something back the the activity corresponding to that context. I've seen no tutorials that show how to use context in this manner.
Lets say I have:
public class LoginActivity {
public int ActivityMember;
public void HandleButtonClick(void){
DownloadFromURL task = new DownloadFromURL(this);
task.execute(url);
}
public void HandleLoginResult(int x){
ActivityMember = x;
}
}
now in a separate java file I have:
private class DownloadFromURL extends AsyncTask<List<NameValuePair>, Long, JSONObject> {
Context context;
public void DownloadFromURL (Context context){
this.context = context;
}
#Override
protected void onPostExecute(JSONObject json) {
context.(<- *my question involves this part of code)
}
}
I'm pretty sure I cant call context.ActivityMember, or context.HandleLoginResult(y) inside onPostExecute, because context is not of the type LoginActivity, its a Context.
So how can I access members or methods belonging to LoginActivity, using it's context?
you can use ((ActivityName)contextName).methodName()
But it is not a good solution. You can try something like this
pass your activity name along with the context to the async class.
protected void onPostExecute(SoapObject result)
{
if(classname.equals("LoginActivity"))
{
((LoginActivity) object).method();
}
else if(classname.equals("MainActivity"))
{
((MainActivity) object).method();
}
}
Easy to do, you just create a method in your activity and call it from the instance you pass through AsyncTask parent class constructor.
Assume you have in your activity some like this:
public void Foo(ArrayList<DataType> data)
{
//Do some with data
}
You then call this method from onPostExecute like this:
#Override
protected void onPostExecute(ArrayList<DataType> data)
{
activity.Foo(data);
}
Where activity is the instance passed through the constructor.
Cheers
This involves basic Object Oriented Programming knowledge.
If you look closely at http://developer.android.com/reference/android/app/Activity.html you can see Activity extends Context, that's why you can get away with passing this to your AsyncTask constructor and having the compiler do the required object slicings.
We can use that to your advantage: Create an abstract class extending Activity (Let's say: DataActivity, just an example though, name it whatever you want) and write a method named onDataDownloadComplete(JSONObject json) (A callback) on it, that you would of call on your AsyncTask's onPostExecute. Make all your activities extend from DataActivity and implement that method. Change the AsyncTask context from Context to DataActivity so you can call the onDataDownloadComplete callback and you are done. Again, as DataActivity would of extend Activity and Activity extends Context, DataActivity or anyhting extending it would be a valid context for the AsyncTask.
Hope you find this useful.
I realized there is another way to achieve what I was trying to do. This takes away the Asyncrony, but for the case of login, I actually do want the UI to be inactive while the app trys to log in.
After I call
asyncTask.execute()
I can call
asyncTask.get()
and that will retrieve the result of doInBackground and allow you to run it on the spot. Alternatively I can use a timeout so I dont block forever:
asynceTask.get(5000, TimeUnit.MILLISECONDS)

Use Asynctask as a private class or with broadcast receiver?

I'm trying to make an application that uses Asynctask. Particularly, I want to make different http petitions with different JSON in different activities without the activity being frozen while the communication is done.
At first I thought to use asynctask as a private inner class in those activities, but I saw that they share a lot of code. So I thought to make a single class and play with broadcast receivers as I need to monitorize when I receive the result of the http petition, and isn't good to interfere with activity directly in the onPostExecute while in a different class.
What I want to know is, what is more efficient and better practice. Make a class that has the shared code and extends asynctask, then doing inner classes for each activity that extends that one or make a single asynctask that sends broadcast and receive them with each activity when needed.
Excuse my poor english, if needed I'll try to specify more clearly.
Thanks in advance
Background
What I want to know is, what is more efficient and better practice. Make a class that has the shared code and extends asynctask, then doing inner classes for each activity that extends that one or make a single asynctask that sends broadcast and receive them with each activity when needed.
I'm unclear as to why these are your only two options. Create a single AsyncTask, such as JsonPetitionTask, then push a new JsonPetitionTask.Data object. This object would contain your URL, your JSON, and any other data you need.
Setting up the AsyncTask
Something like this:
public class JsonPetitionTask extends AsyncTask<JsonPetitionTask.Data, Integer, Boolean> {
protected Boolean doInBackground(JsonPetitionTask.Data... args) {
for (int i = 0; i < args.length; i++) {
JsonPetitionTask.Data data = args[i];
// Send your JSON; check for errors, and return false if needed.
if (isCancelled()) break;
}
return true;
}
protected void onProgressUpdate(Integer... progress) {
// Show progress?
}
protected void onPostExecute(Boolean result) {
// result is your success true/false.
}
public static class Data {
public String jsonContent;
public String petitionUrl;
public Data(String content, String url) {
jsonContent = content;
petitionUrl = url;
}
}
}
Calling the JsonPetitionTask
Then you can call it like so:
JsonPetitionTask.Data data = new JsonPetitionTask.Data(myJSON, myURL);
new JsonPetitionTask().execute(data);
And voilĂ , you've executed your AsyncTask using only one class with no receivers.
Implementing a callback
Now, if you want to register a callback (something to execute that is specific to the calling code), that's a bit trickier. If this is part of what you're looking for, I'll be glad to edit this post and explain it.
To add a callback, we can use the Runnable class to execute some code after the job is done.
Firstly, we need to add a new field in the Data inner class:
public Runnable callback;
Next, before we call execute(), we need to add a new callback to our data object.
data.callback = new Runnable() {
public void run() {
// Whatever code you want to run on completion.
}
};
Third, in the JsonPetitionTask class, we need a list of things to run:
private ArrayList<Runnable> mRunnables = new ArrayList<Runnable>();
Make sure, in each iteration of the doInBackground() loop, that you do mRunnables.add(data.callback);.
Lastly, in onPostExecute(), we need to call this:
protected void onPostExecute(Boolean result) {
for (Runnable r : mRunnables)
if (r != null) r.run();
}
I do realize I didn't send result to the Runnable, however I didn't feel like implementing a new Runnable type just to handle that. If you need this, I guess that's a bit of homework for you!
The way I found the best is just simply create public class that extends AsyncTask and then you just override onPostExecute function in every activity you use it.
Example:
MyDataTask dataTask = new MyDataTask() //you can add your parameters in class constructor
{
#Override
protected void onPostExecute(Object result) //replace Object with your result type
{
MyActivity.this.doStuff(result); //use result in current activity
}
};
you can also create some custom functions to set private variables in datatask
dataTask.AddParam("user", username);
dataTask.AddParam("pass", pass);
and then just execute it with your args...
dataTask.execute(myArgs);
I have used Async task class as single class. And for every Webservice call i have used unique IntentFilter to Broadcast response.
Put that Broadcast receiver in every class. You have perfect solution.
Its working well.

Categories

Resources