DialogFragment getActivity() "может быть нулевым" предупреждением в AndroidStudio 3.0.1

Самый близкий существующий вопрос, который я могу найти в этом вопросе, - Android-версия 3.0 для подсказок для ссылок на активность, но это не помогает.

Используя AndroidStudio 3.0.1, у меня есть DialogFragment, где я делаю это обычное дело:

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

У меня есть предупреждение, напоминающее мне, что Argument 'getActivity()' might be null.

Я понимаю, почему getActivity() может быть нулевым, и я понимаю, как это проверяется проверкой lint (из аннотации @Nullable).

Мой вопрос: все очень хорошо и хорошо, что getActivity() может быть нулевым, но практически как я должен обращаться с этим изящно и аккуратно? onCreateDialog должен возвращать Dialog (из-за аннотации суперкласса @Nullable), поэтому у меня должен быть контекст Activity для его создания.

Я мог предположить, что onCreateDialog никогда не будет вызываться, если DialogFragment не привязан к Activity, но все же - как я могу устранить неопрятное предупреждение о линге?

Ответ 1

Ответ @Niklas объясняет, почему вы получаете это предупреждение сейчас. Я хотел бы поделиться своими мыслями о том, что вы на самом деле должны делать.

Прежде всего, все, что делает эта добавленная обнуляемость, - это выявление дефекта старого дизайна, который присутствовал все эти годы - этот метод всегда мог вернуть ноль (например, отсоединенный фрагмент).

Я бы предпочел, чтобы они аннотировали возвращаемое значение как @NonNull и выдавали исключение внутренне, если этот метод вызывается, когда Activity на самом деле имеет значение null, но я понимаю, что это нарушит обратную совместимость и, как таковую, очень рискованно (хотя вряд ли я понимаю, почему Кто-нибудь вызывает этот метод, когда активность может быть нулевой).

Итак, что нам с этим делать?

Прежде всего, поскольку функциональность не изменилась вообще, если рассматриваемый код уже работал, тогда сделайте то, что предложил @CommonsWare - либо подавьте предупреждение, либо проигнорируйте его.

Вы также можете заключить каждый вызов в нулевую проверку, например, с исключением.

Однако я собираюсь поместить этот метод в мой BaseDialog (который расширяется всеми другими диалогами):

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

Обратите внимание, что все эти параметры фактически утверждают, что вы на самом деле не ожидаете, что будет возвращено значение NULL, и это нормально при сбое приложения, если это произойдет. Поэтому я сказал, что предпочел бы иметь это в коде библиотеки поддержки.

Редактировать:

Для поддержки фрагментов был добавлен новый метод - requireActivity(). Этот метод эквивалентен getActivityNonNull() описанному выше (хотя он выдает IllegalStateException если он не присоединен к Activity).

Используйте этот метод вместо getActivity() и у вас все получится.

Ответ 2

Это дубликат предупреждений - Android Studio 3.0 для ссылок на активность.

TL;DR; getActivity() получил с помощью Support lib 27.0.0 аннотацию @Nullable и инструменты статического анализа теперь выбирают.

Ответ 3

Эти методы были добавлены в выпуске Revision 27.1.0: фрагменты теперь имеют requireContext(), requireActivity(), requireHost() и requireFragmentManager(), которые возвращают объект NonNull эквивалентных методов get или генерируют исключение IllegalStateException.

Ответ 4

Для тех из вас, кто хочет увидеть исходный код метода requireActivity():

 @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; 
     }
 }