3

I am getting an error message that activity has already been destroyed when FragmentManager is called. Is there a check that the FragmentManager can do before making it's transaction call or do I need to get the activity and check that it is not null or !activity.isFinishing() ? Are there any other checks I need to do? This is what I used to do but not sure this is still the way to do it? Just curious why fragment manager would not know about the state of the activity ... I need to cover both the case where the activity is about to be destroyed and where it has already been destroyed(). In either case I don't want to commit the transaction.

UPDATE: For API 17+ activity.isDestroyed() is available. For API < 17 still need to confirm that activity.isFinishing() will detect a destroyed activity or if there is another way to do this?

  if ((activity != null) && !activity.isFinishing()) {
      fm.FragmentTransaction fragmentTransaction = 
      fm.beginTransaction().replace(R.id.fragment_container, mFeedFragment).commitAllowingStatelessLoss();
  }
gitsensible
  • 551
  • 1
  • 8
  • 19

2 Answers2

4

Try this boolean isDestroyed ()

Returns true if the final onDestroy() call has been made on the Activity, so this instance is now dead.

the following are method which your to perform any task before Activity is going to become invisible.

  • onDestroy() - Perform any final cleanup before an activity isdestroyed
  • isFinishing - Check to see whether this activity is in the process of finishing,
  • onStop -Called when Activity no longer visible to the user.
  • onPause - Called as part of the activity lifecycle when an activity is going into the background, but has not (yet) been killed.
  • onBackPressed - Called when the activity has detected the user's press of the back key. The default implementation simply finishes the current activity, but you can override this to do whatever you want.
AskNilesh
  • 67,701
  • 16
  • 123
  • 163
  • But is this necessary if isFinishing() is also called()? – gitsensible Jun 23 '17 at 04:10
  • I think isFinishing() will probably return true once it has already been destroyed. What do you think? – gitsensible Jun 23 '17 at 04:15
  • @gitsensible isFinishing method return true If the activity is finishing, else returns false. – AskNilesh Jun 23 '17 at 04:18
  • Ok, so looks like its necessary to check for finishing or destroyed both. After all if it's finishing it could be destroyed any millisecond after the call returns false for isDestroyed(). At least theoretically. – gitsensible Jun 23 '17 at 04:29
  • In fact the isFinishing() returns true if something (this activity, another activity, ...anything) has called finish() on your activity.. You can use the isFinishing in your lifecycle methods to detect wether the activity is stopping because of system or finish() call... – convexHull Jun 23 '17 at 04:31
  • @convexHull In my case, and I think for many others the plan is not to do the fragment transaction either when it's finishing or certainly once it's been destroyed. Just checking if it's already been isDestroyed() is not enough because it could be destroyed a millisecond later. Likewise just checking if its isFinishing() is not enough unless the method isFinishing returns true for a destroyed activity which the documentation does not indicate. Apparently the FragmentManager will just throw Exception in the case of destroyed activity. So there needs to be a standard way to check for this. – gitsensible Jun 23 '17 at 06:18
  • Just found out that isDestroyed() is API level 17+ only. Now wondering if the isFinishing() alone will work for API < 17 ? – gitsensible Jun 23 '17 at 06:30
  • @gitsensible As I mentioned isFinishing() will be true only in case that someone (not the system) has called finish() on your activity... If you will test both methods on Main thread then it should be OK, tak activity will not change the state until method where you are calling isFinished() ends - All the state methods (onStop(), onPause(), onDestroy() etc... are called on Main thread. – convexHull Jun 26 '17 at 10:49
3

The best bet would be to check if Activity.isFinishing(). If true, then it is not safe to work with such Activity, if false at least we know the Activity's destruction has not been triggered.

Reasoning

  • Checking if an Activityis null does not mean the Activity is destroyed. The Activity can be destroyed and still hold data created in it.
  • Checking if Activity.isDestroyed() from the docs states,

    Returns true if the final onDestroy() call has been made on the Activity, so this instance is now dead.

    What does DEAD instance means idk, I could not find out on the internet a complete answer but clearly it does not mean null in this scenario. Hence, dead instance != null.

  • Checking if Activity.isFinishing() from the docs states,

    Check to see whether this activity is in the process of finishing, either because you called finish() on it or someone else has requested that it finished. This is often used in onPause() to determine whether the activity is simply pausing or completely finishing.

  • Calling Activity.finish() will call Activity.onDestroy(). However, after doing some tests with help of Robolectric it holds that after calling Activity.finish()

    Activity.isFinishing() == true Activity.isDestroyed() == false

    Why, check what exactly Activity.finish() method is doing?

ArtiomLK
  • 2,120
  • 20
  • 24