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)
Related
I've used the AsyncTask example from vogella website, I've created a class file with it.
I'm calling it from Activity A to update the postalcode's TextView, it's working.
I'm wondering how can I call the same AsyncTask from Activity B to update another postal code TextView.
So one AsyncTask, 2 calls from different Activities to update different TextViews.
I've to do something onPostExecute(), right?
Some example code, is much appreciated.
Thanks in advance
You can (I guess) pass the TextView to the AsyncTask when you instantiate it.
All without the IDE open so apologies if the syntax is off...
public class ExampleTask extends AsyncTask<Void, Void, Void> {
private TextView targetTextView;
public ExampleTask(TextView target) {
targetTextView = target;
}
#Override
protected String doInBackground(Void... orSomething) {
//do work and get a value I guess
}
#Override
protected void onPostExecute(String result) {
targetTextView.setText(result);
}
}
Then you'd call this:
ExampleTask task = new ExampleTask(theTextViewToUpdate);
task.execute();
You'd want to be careful about the scope of the task objects you instantiate as that reference to a TextView could end up leaking memory from your activities.
Here I am not good, but you can try
It is possible to reuse AsyncTask for different Activities.
For this you must take different parameter from different Activities.
In AsyncTask Class initiate a constructor with a case parameter (which is described in other activities) which will decide ,it is called by Activity A or B or C.
Now use switch case statement and move ahead.
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.
I am trying to call this method:
public static void trackFunXStartActivity(Activity a)
{
s.startFunXActivity(a);
}
I'm trying to call it using this code in my LayoutsActivity.java:
public void onStart() {
TrackFunX.trackFunXStartActivity(LayoutsActivity);
}
but I'm not sure how to create or reference the Activity that I can pass to trackFunXStartActivity(Activity a). I don't think I can pass LayoutsActivity as an Activity.
How do I go about instantiating or reference an activity in LayoutsActivity.java to pass to trackFunXStartActivity.
I'm a Android newbie and have done some searches on StackOverflow but didn't see anything to help with this questions.
Thanks
take a static context for the LayoutsActivity like
static Context context;
and in the oncreate method use
context = LayoutsActivity.this
and finally you can use this context in the class where you need
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
I would like to achieve the following behaviour, but I'm not sure how:
User start an activity
Activity starts an AsyncTask
User performs some action that creates a new activity
The AsyncTask finishes and somehow returns the result to the new activity
Is there a way of achieving this behaviour?
Thank you
Create a Service that itself spawns its own thread and does your background processing. You can bind your activities to the service so you can call back into an activity when your processing is complete.
I've been using a variation of what was suggested by Chris:
Start by creating an IntentService, which is the easiest kind of Service to create. Then use SharedPreferences to indicate the state of your IntentService and share values between your Service and Activities. Your Activity can register itself as an OnSharedPreferenceChangeListener in order to know when your Service is done doing work and/or another SharedPreference it cares about has changed.
With IntentService, all you need to do is override the onHandleIntent method. Everything inside onHandleIntent will run on a background thread.
This is a way to do exactly what you want, assuming that the result is an int. You can extend this property, using a parcelable object. Probably, using a Service is still the best choice.
1) Create a class, called Result, that is a wrapper for your result. It must implement the Parcelable interface:
public class Result implements Parcelable {
private int result;
public Result(int i) {
super();
result = i;
}
public void setResult(int result) {
this.result = result;
}
public int getResult() {
return result;
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(result);
}
public static final Parcelable.Creator<Result> CREATOR = new Parcelable.Creator<Result>() {
public Result createFromParcel(Parcel in) {
return new Result(in);
}
public Result[] newArray(int size) {
return new Result[size];
}
};
public Result(Parcel in) {
result = in.readInt();
}
}
2) Now, you can use a Result object as a private variable of the first activity:
public class FirstActivity extends Activity {
private Result result;
....
}
3) In your firstActivity, you can start an AsyncTask with a line like this:
new MyAsyncTask(result).execute();
4) Your AsyncTask can be made in this way:
class MyAsyncTask extends AsyncTask<Void, Void, Void> { // you can modify types as you want
Result result;
public MyAsyncTask(Result result) {
this.result = result;
}
....
public mySetResult() {
result.setResult(...); //set your value
}
....
}
5) When you start the second Activity, you can pass your result object to the second activity:
Intent i = new Intent(getApplicationContext(), SecondActivity.class);
i.putExtra("parc", result);
startActivity(i);
6) Finally, from the second activity, you can obtain the result using this code:
Result res = (Result) getIntent().getParcelableExtra("parc");
For more details about parcelable object, can see Android Developer
A Service is a component that allows some code to have a separate lifetime outside of activities without interacting with the user. As others have mentioned, that's certainly one option to consider. If you go with that, IntentService is the easiest way to make the work asynchronous.
However, you could continue to use AsyncTask and just add some code to signal that it's "complete". This is the case when the background work no longer matters if your application is killed, and you're OK with your app being killed before this work completes if the user leaves the application. Another way to see this is if the result of the AsyncTask only matters to either/both of these two activities and not outside. This is an important difference in requirements from needing a Service which again, provides a lifetime outside of activities.
To pass the data, take a look at this doc. There are a lot of ways you could tackle this, but for this kind of thing I prefer a pseudo-singleton approach. (I don't like to use SharedPreferences to pass data, because frankly I don't think that's what the class is for. I prefer this pseudo-singleton approach over a pure singleton because it's more testable. Android uses the singleton approach all over the place though.) I'd create a reference to some sort of AsyncTask registrar class in the Application object. As the Application object is accessible from both activities, the first one can register your AsyncTask with the registrar and the second one can get that AsyncTask and register to listen for completion if it hasn't already finished.