Access instance variables from an activity inside

2019-08-02 16:07发布

问题:

I have an AsyncTask (in a separate file) which is invoked on an activity. When I instantiate the AsyncTask, I send the activity as a param. How can I access the acitivity's instance variables from the onPostExecute method of the AsyncTask?

Thanks!

回答1:

You must be careful when passing an Activity or Context to an AsyncTask that is not an inner (non-static) class of an Activity - this is because in this case the lifetime of the Activity/Context and the AsyncTask are different, and if you hold on to an Activity/Context for longer than you should you will cause memory leaks.

Rather than holding onto the Activity or activity context itself in your AsyncTask you should keep a WeakReference to the Activity. This will ensure that the memory associated with the Activity can be reclaimed by the garbage collector (GC) when needed.

public class MyTask extends AsyncTask<..., ..., ...> {
    private WeakReference<MyActivity> mParentActivity = null;

    public MyTask(MyActivity parentActivity) {
        mParentActivity = new WeakReference<MyActivity>(parentActivity);
    }

    @Override
    public ... doInBackground(... params) {
        // do some stuff

        // now we do something that requires the context
        if (mParentActivity.get() != null) {
            // the WeakReference is still valid and hasn't been reclaimed
            // by the GC
            final MyActivity parentActivity = mParentActivity.get();
            parentActivity.doSomething();
        }

        // return result
    }
}

When passing a Context always try to use the ApplicationContext where possible as this is the longest-lived context.



回答2:

Similar to Programmer Bruce's answer but instead of passing the Activity as a Param through the AsyncTask itself, simply add a constructor to take the parent Activity. Example from my own code...

public class FileDownloader extends AsyncTask<..., ..., ...> {
    private MyActivity parentActivity = null;

    public FileDownloader(MyActivity parentActivity) {
        this.parentActivity = parentActivity;
    }
}

When you create it in your Activity just do this...

FileDownloader fdl = new FileDownloader(this);
fdl.execute(...);

EDIT: In reply to your comment, make sure mLogin is declared as public then use...

parentActivity.mLogin

If that doesn't work, try...

((MyActivity)parentActivity).mLogin


回答3:

You can extend from AsyncTask<Object, x x>, and you can then pass in any number of arbitrary parameters you like, no need to pass around reference to the whole Activity.

 new CustomTask().execute(param1, param2, param3);

Which you can reference in your doInBackground:

 public Void doInBackground(Object... params) {
    Integer id = (Integer) params[0];
    String name = (String) params[1];
    ....
 }