Ares
Ares

Reputation: 1461

Async Task started and ended in different activities

I would like to achieve the following behaviour, but I'm not sure how:

  1. User start an activity
  2. Activity starts an AsyncTask
  3. User performs some action that creates a new activity
  4. The AsyncTask finishes and somehow returns the result to the new activity

Is there a way of achieving this behaviour?

Thank you

Upvotes: 1

Views: 2070

Answers (4)

kabuko
kabuko

Reputation: 36302

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.

Upvotes: 0

Vito Gentile
Vito Gentile

Reputation: 14386

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

Upvotes: 0

Eric Levine
Eric Levine

Reputation: 13564

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.

Upvotes: 0

Chris
Chris

Reputation: 23181

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.

Upvotes: 5

Related Questions