33

The closest existing question I can find regarding this is Android Studio 3.0 lint warnings for references to activity, but it does not help.

Using AndroidStudio 3.0.1, I have a DialogFragment where I do this usual stuff:

    @Override
    @NonNull
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
        ...

I have a lint warning moaning at me that Argument 'getActivity()' might be null.

I understand why getActivity() may be null, and I understand how the lint inspection knows this (from the @Nullable annotation).

My question is: It's all very well and good that getActivity() may be null, but practically how am I supposed to deal with this gracefully and tidily? onCreateDialog must return a Dialog (because of the superclass' @Nullable annotation) so I must have the Activity context to create it.

I could assume that onCreateDialog will never be called if the DialogFragment isn't attached to an Activity, but still - how do I address the untidy lint warning?

Trevor
  • 10,903
  • 5
  • 61
  • 84
  • 6
    "how do I address the untidy lint warning?" -- suppress it and move on. – CommonsWare Dec 27 '17 at 15:55
  • why don't you use getContext() – vikas kumar Dec 27 '17 at 16:05
  • Maybe you could rely on onActivityCreated or onAttach (depracated) which would give you valid reference. Then use it instead of getActivity() ? – marcinj Dec 27 '17 at 16:18
  • 3
    @CommonsWare is it specifically `@SuppressWarnings("ConstantConditions")` you're recommending? – Trevor Dec 27 '17 at 16:22
  • @vikaskumar well, that is `@Nullable` too. – Trevor Dec 27 '17 at 16:23
  • @marcinj That is an approach I had considered, although I am concerned it could have the potential to introduce a leak (even though the fragment is bound to the host activity lifecycle). Plus, although I haven't actually tested it, I assume that lint would blurt throw a 'could be null' warning. – Trevor Dec 27 '17 at 16:25
  • 2
    If that's what the quick-fix suggests, and it works, then yes. Or, mentally suppress it, if you find the annotations to be more annoying than the highlighted code segments. Or, put a `null` check in and throw an `IllegalStateException` in the scenario where it is actually `null` (which shouldn't happen). – CommonsWare Dec 27 '17 at 16:26
  • Yep, very good point: Chucking an exception is another one I had considered, because technically if that method gets called without there being an associated activity, then that's an invalid program condition. Another point to mention is that the superclass' method makes a reference to getActivity(). Given the comments you gents have kindly made, I'm now more than happy with ignoring (or just suppressing) the lint warning. At least I now know that this is one of those times that suppressing or ignoring is the only realistic course of action, and I've not missed a better way. – Trevor Dec 27 '17 at 16:31

4 Answers4

39

The answer by @Niklas explains why you get this warning now. I would like to share my thoughts about what you should actually do.

First of all, all this added nullability does is exposing the old design deficiency that was present all these years - this method could always return null (e.g. Fragment detached).

I would prefer if they annotated the return value as @NonNull and throw exception internally if this method is called when the Activity is actually null, but I understand that it would break backward compatibility and as such very risky (though I can hardly see why would anyone call this method when the Activity can actually be null).

So, what should we do about it?

First of all, since the functionality didn't change at all, if the code in question already worked then do what @CommonsWare suggested - either supress the warning or ignore it.

You could also wrap each call into null check with e.g. exception.

What I'm going to do, however, is to put this method in my BaseDialog (which is extended by all other dialogs):

protected FragmentActivity getActivityNonNull() {
    if (super.getActivity() != null) {
        return super.getActivity();
    } else {
        throw new RuntimeException("null returned from getActivity()");
    }
}

Note that all these options effectively state that you don't really expect null to be returned and is OK with app crashing if that happens. That's why I said that I would prefer to have this in support library code instead.

Edit:

A new method was added to support Fragments - requireActivity(). This method is equivalent to getActivityNonNull() descried above (though it throws IllegalStateException if not attached to Activity).

Use this method instead of getActivity() and you should be good.

Vasiliy
  • 16,221
  • 11
  • 71
  • 127
  • 2
    The method was added in february 2018 - [version 27.1.0](https://developer.android.com/topic/libraries/support-library/revisions#27-1-0) – Soon Santos Aug 30 '18 at 19:20
  • Perfect! I usually do not like suppressing or ignoring lints either. Grateful for this recent addition. Below is source code block for the same. @NonNull public final FragmentActivity requireActivity() { FragmentActivity activity = this.getActivity(); if (activity == null) { throw new IllegalStateException("Fragment " + this + " not attached to an activity."); } else { return activity; } } – Avid Programmer Sep 13 '18 at 17:51
  • So, with this recently added method requireActivity(), we don't get an NPE, but we get a RuntimeException, which equates to the same behavior... You go Google! – Tharkius Jan 09 '19 at 16:51
6

These methods was added in Revision 27.1.0 Release:Fragments now have requireContext(), requireActivity(), requireHost(), and requireFragmentManager() methods, which return a NonNull object of the equivalent get methods or throw an IllegalStateException.

3

This is a duplicate of - Android Studio 3.0 lint warnings for references to activity.

tldr; getActivity() got with Support lib 27.0.0 the annotation @Nullable and static analyze tools pick that up now.

Niklas
  • 23,674
  • 33
  • 131
  • 170
0

For those of you who want to see the source code for the requireActivity() method:

 @NonNull 
 public final FragmentActivity requireActivity() { 
     FragmentActivity activity = this.getActivity();
     if (activity == null) { 
         throw new IllegalStateException(
             "Fragment " + this + " not attached to an activity."
         );
     } else {
         return activity; 
     }
 } 
Avid Programmer
  • 1,081
  • 1
  • 11
  • 20