13

At the docs for Fragment.getActivity() it says: Return the FragmentActivity this fragment is currently associated with. May return null if the fragment is associated with a Context instead.

But how can a fragment not be associated with an activity? I mean, don't I always need an activity to show anything in Android?

Nemo
  • 728
  • 1
  • 4
  • 16

3 Answers3

6

Fragments are not required to be associated with a FragmentActivity. Instead, they are actually associated with a FragmentController, which FragmentActivity happens to create and manage on your behalf, calling the appropriate dispatch methods as necessary as the hosting activity is created, started, etc.

This level of indirection is how Facebook's Chat Heads (which displayed a Window managed by a Service) is able to reuse the same Fragment instances that a FragmentActivity uses and how building Navigation apps for Android Automotive (which use a CarAppService to display the Automotive app) allows you to also reuse Fragments.

Of course, if your Fragment is always created from within one of your Activities, then, yes, you can absolutely assume that requireActivity() will return a FragmentActivity anytime isAdded() returns true - i.e., between onAttach() and onDetach(). That does indeed include in lifecycle methods such as onViewCreated() or anything associated with your Fragment's views (such as an OnClickListener).

ianhanniballake
  • 191,609
  • 30
  • 470
  • 443
  • 1
    That's exactly what I was looking for. So it's safe between the expected lifecycle stages *if* you are using it exclusively from Activities. The framework won't attach it to an Activity-less Context without you explicitly doing so. – Tenfour04 Nov 30 '20 at 00:08
0

1- "... is it truly safe to call requireActivity() ...?" No, as you can see from the implementation of the method:

/**
 * Return the {@link FragmentActivity} this fragment is currently associated with.
 *
 * @throws IllegalStateException if not currently associated with an activity or if associated
 * only with a context.
 * @see #getActivity()
 */
@NonNull
public final FragmentActivity requireActivity() {
    FragmentActivity activity = getActivity();
    if (activity == null) {
        throw new IllegalStateException("Fragment " + this + " not attached to an activity.");
    }
    return activity;
}

In case the activity is null, this method will throw an exception and if you had not handled this exception as probably you might not have handled nullity of the getActivity() the app would crash. Compiler does not show a warning simply because there is a null check in this method.

2- "But how can a fragment not be associated with an activity? I mean, don't I always need an activity to show anything in Android?" True. An attached fragment needs an activity, but, simply because a getActivity() method is called does not mean its fragment is in attached state. So, it might happen in listeners or some callbacks, that one might call getActivity() while activity is destroyed eg. due to a rotation. Because of such situation you should check the nullity of returned value by getActivity(). When the activity is destroyed, the Associated context is not the activity's context. There are several interesting insights into this matter and good suggestions that you can read about them here: getActivity() returns null in Fragment.

Sina
  • 2,683
  • 1
  • 13
  • 25
  • I understand that `requireActivity()` can throw an exception. The question is, at what stages of the lifecycle can we assured that it will not throw an exception? If there aren't any, then the method would not exist. Sometimes you want to adjust your view padding using values from the parent layout in the attached activity. You don't want to modify the padding multiple times, but you don't want to call the code inside an if statement because then it might be missed. – Tenfour04 Nov 26 '20 at 22:32
  • You are safe between onAttach and onDetach. In other lifeCycle methods you write your code as you wish, just check for null while getting activity. – Sina Nov 27 '20 at 09:54
  • And please read the link for more concise and detailed solutions. – Sina Nov 27 '20 at 10:15
  • "You are safe between onAttach and onDetach" - but why did Google recently deprecate `onAttach(Activity)` then, telling us to use `onAttach(Context)`? To me, this sounds like `onAttach(Context)` can be called even though there is no activity, just a context. But why? What am I missing? – Nemo Nov 28 '20 at 09:33
  • In onAttach(Context), if that context is of an activity, fragment gets attached, and you can expect other lifeCycle methods to be called. But, if it is not, onDetach will be called immediately. Still, you should check for nullity since if a listener or callback call getActivity after onDetach it gets null. But if onAttach is called and onDetach has not, getActivity won't return null. – Sina Nov 28 '20 at 11:05
0

"But how can a fragment not be associated with an activity?" - You can always create an instance of your fragment without attaching it to any activity. However, it will just won't show up in the screen (i.e. the lifecycle methods will not kick in), if you do not attach it to an activity. This is an interesting thread to read.

"I mean, don't I always need an activity to show anything in Android?" - Yes.

I found this google developer training link very useful to understand the lifecycle callbacks between activity and fragment. Quoting from that link here.

Each lifecycle callback for the Activity results in a similar callback for each Fragment, as shown in the following table. For example, when the Activity receives onPause(), it triggers a Fragment onPause() for each Fragment in the Activity.

enter image description here

Also, the SO link @Sina posted in his answer has some insights about when you might expect the getActivity to return null.

Reaz Murshed
  • 23,691
  • 13
  • 78
  • 98