1

I'm still puzzled by the fact, that Google puts a method in the Android API that sometimes works and sometimes not; namely Fragment.getActivity(). I know, I can check if the result is null and there is also the isAdded() method. However, how should I proceed when these checks have a negative result? When I've come this far, there is a reason I want to access the Activity, like accessing Resources or Preferences or do one of the zillion things that require a Context in Android.

I could simply not do whatever I was about to do. However, I think it would be a poor user experience, if my App sometimes executes the action the user selected and sometimes not. In fact, I think letting my App just crash wouldn't be much worse.

Or I could tell the user about the detached activity and that he should try again later. But wait, Toast requires a Context, so I can't even do that.

Or should I just wait for the Activity to be reattached like this?

Activity activity = getActivity();

while (activity == null) {
    Thread.sleep(10);
    activity = getActivity();
}

(I'm not seriously suggesting this, I merely want to illustrate how desperate I am)

Maybe I'm thinking about this all wrong. Maybe I'm trying to do things the wrong way. Maybe there is a school of thought about how to use Fragments that I haven't heard of. However, if I should avoid to access the Activity in a Fragment, why is the getActivity() method there in the first place?

The particular problem I'm struggling with right now is that in a PreferenceFragment in an OnSharedPreferenceChangeListener I want to give the user a Toast message:

Toast.makeText(getActivity(), message, Toast.LENGTH_SHORT).show();

That works most of the time, but it sometimes crashes because getActivity() returned null.

user1785730
  • 3,150
  • 4
  • 27
  • 50
  • "it sometimes crashes because getActivity() returned null." -- you need to unregister the listener at an appropriate point, such as `onDetach()`. "I merely want to illustrate how desperate I am" -- it wouldn't work anyway. "why is the getActivity() method there in the first place?" -- you either need to ensure that asynchronous stuff respects the fragment lifecycle (e.g., use `LiveData`) or that it can cope with the fact that the asynchronous stuff happened to complete at an inopportune time. – CommonsWare Jan 11 '19 at 18:00
  • 1
    You seem to have a design flaw. If you have an action that is not tied to the Fragment, then it belongs in the Activity. In any case, you can wait till tomorrow for the Activity to reattach, for it will never happen. See the Fragment lifecycle page. – lionscribe Jan 11 '19 at 20:36
  • @lionscribe: I think I do have a design flaw and a lack of understanding of Fragments. I don't know how to untangle it. Consider this example: The activity really doesn't do anything but start the Fragment. On some Fragment the user launches an action that for whatever reason requires a Context, Resources or what not. How would I go about that? – user1785730 Jan 13 '19 at 17:17
  • I posted an answer, as comments don't allow long ones. – lionscribe Jan 13 '19 at 18:06

2 Answers2

5

In usual cases, once attached, you will always have the Activity in the Fragment, as the Activity will only be detached once the Fragment is being destroyed (and will never be reattached). See the Fragment Lifecycle graph from Android at https://developer.android.com/guide/components/fragments. The only issue, I can think of, is when you are using another thread or posting Runnable, with a callback referencing Fragment. In that case, the callback can be called after Fragment is detached and destroyed. Now, usually in that case, you want to dump what you are doing, and exit, so just check if getActivity is null and do nothing. If you do have to do something even if Fragment is destroyed, then if you need the context only for resources or the like, you can safely use the ApplicationContext which you can safely hold onto for life of app. If you need the Context for the UI, like to show user a Toast, an ApplicationContext will not work. In that case, you will have to redesign your code, that the Activity is the one that deals with the callbacks and functions, rather than the Fragment. This is all assuming the Activity will still be around.

lionscribe
  • 3,413
  • 1
  • 16
  • 21
  • [This answer](https://stackoverflow.com/a/53975199/1785730) says the Fragment is not necessarily attached to its Activity during the Fragments `onCreate()` method. – user1785730 Jan 15 '19 at 01:22
  • @user1785730 I don't think that answer is correct. What is happening there is that you are still holding on to the Fragment after it was destroyed. – lionscribe Jan 15 '19 at 06:06
-1

at first define in your fragment,

  YourActivity mContext; 

and then override this in your fragment

@Override
public void onAttach(Context context) {
    mContext = (YourActivity) context;
    super.onAttach(context);
}

and use mContext in place of getActivity()

Amit
  • 72
  • 4