3

In activity's onCreate I first check some remote data, if not already checked and then update the UI:

private static WeakReference<MainActivity> wrActivity = null;

protected void onCreate(final Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);

  wrActivity = new WeakReference<MainActivity>(this);
  // ...
}

private class InitTask extends AsyncTask<Object, Void, Bundle> {
  @Override
  protected Bundle doInBackground(Object... params) {
    // checking some (network) stuff

    return (Bundle) params[0];
  }

  @Override
  protected void onPostExecute(final Bundle savedInstanceState) {
    if (wrActivity.get() == null || wrActivity.get().isFinishing()) {
      return;
    }

    updateUi(savedInstanceState);
  }
}

private void updateUi(Bundle savedInstanceState) {
  Log.d(getClass().getSimpleName(), "updateUi()");

  if (savedInstanceState == null) {
    resetActionBar();
  }

  initPagerAndTabs(savedInstanceState);

  // ...
}

private void initPagerAndTabs(Bundle savedInstanceState) {
  Log.d(getClass().getSimpleName(), "initPagerAndTabs()");
  mTabNames = getResources().getStringArray(R.array.tabs);

  mAdapter = new FragmentAdapter(getSupportFragmentManager());
  mPager = (ViewPager) findViewById(R.id.pager);
  mPager.setAdapter(mAdapter);
  mPager.setOnPageChangeListener(mAdapter);
  // ...
}

But, sometimes, my app crashes with this:

java.lang.IllegalStateException: Activity has been destroyed
  at android.support.v4.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:1376)
  at android.support.v4.app.BackStackRecord.commitInternal(BackStackRecord.java:595)
  at android.support.v4.app.BackStackRecord.commitAllowingStateLoss(BackStackRecord.java:578)
  at android.support.v4.app.FragmentPagerAdapter.finishUpdate(FragmentPagerAdapter.java:139)
  at android.support.v4.view.ViewPager.setAdapter(ViewPager.java:415)
  at com.mypackage.MainActivity.access$9(MainActivity.java:1358)
  at com.mypackage.MainActivity$InitTask.onPostExecute(MainActivity.java:1)

The line 1358 is exactly whis one:

private void updateUi(Bundle savedInstanceState) {

So, the WeakReference (pattern) does not save me from AsyncTask returning result to a different MainActivity.

What is the best approach in this case? ServiceIntent?

Saran
  • 3,845
  • 3
  • 37
  • 59
  • 1
    weakreference does not prevent anything from being GCed, but it has nothing to do with this case. The fact that an Activity is destroyed is related to its life cycle. You possibly want to either bind to a service in the activity, or simply ignore the result of your asynctask if the activity is destroyed. Possibly calling `cancel` on the AsyncTask when your activity is paused. – njzk2 Oct 06 '14 at 16:16
  • Maybe the same issue as here : http://stackoverflow.com/questions/15207305/getting-the-error-java-lang-illegalstateexception-activity-has-been-destroyed – ToYonos Oct 06 '14 at 16:22

2 Answers2

2

The WeakReference will not be set to null until the activity is GC'd, which might be a while after it has been destroyed. After "isFinishing()", add a check for "isDestroyed()". This requires API level 17, so you might need to implement it yourself (a boolean field that is set to false in onDestroy).

Also, for neatness, only use a single call to WeakReference.get(). Theoretically, the GC can run in between the two calls, giving you a NullPointerException.

Black Mantha
  • 1,147
  • 8
  • 11
  • Your point about the single call to `WeakReference.get()` is absolutely correct. One must `get()` the referenced object and then work with it directly. Any subsequent use of the `WeakReference` is an invitation to `NullPointerException`. – Erick G. Hagstrom Mar 02 '16 at 17:24
0

Your private non static class InitTask hold reference to your activity. You can read this about it.

Alexey Subbota
  • 938
  • 6
  • 23