Тост в фрагментах Android, показывающих нулевой указатель expn

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

Toast.makeText(getActivity(), "Connection Failure", Toast.LENGTH_LONG).show();

и мои журналы ST ниже.

Fatal Exception: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String android.content.Context.getPackageName()' on a null object reference
   at android.widget.Toast.(Toast.java:103)
   at android.widget.Toast.makeText(Toast.java:256)

используйте getContext () вместо getActivity ()

Syed Danish Haider 12.09.2018 09:33

Привет, Сайед Даниш Хайдер. спасибо за ваш ответ ... не могли бы вы помочь мне разобраться с небольшим объяснением вашего предложения ....

Bharat Kumar 12.09.2018 09:35

Я отправил ответ для справки, примите мой ответ, если он полезен

Syed Danish Haider 12.09.2018 09:39

Сохраните контекст приложения в глобальной переменной и используйте эту глобальную переменную вместо getActivity ()

Kushal 12.09.2018 10:29

@Kushal Мне это нравится - мы, должно быть, думаем одинаково. Я добавлял это в свой ответ примерно в то же время, когда вы это разместили. Я также включил ссылку на код, в котором это делается с использованием шаблона Singleton. Может быть, не во всех случаях, но это отличный способ решения таких сложных случаев.

Richard Le Mesurier 12.09.2018 10:34
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
5
1 213
6
Перейти к ответу Данный вопрос помечен как решенный

Ответы 6

Ваша активность context в этой строке равна нулю:

Toast.makeText(getActivity(), "Connection Failure", Toast.LENGTH_LONG).show();// getActivity() is null

Чтобы избежать сбоя, используйте это:

if (getActivity() != null)
   Toast.makeText(getActivity(), "Connection Failure", Toast.LENGTH_LONG).show();

Иногда getActivity () или getContext () может вызывать исключение нулевого указателя, когда фрагмент не связан с Activity. Так что используйте метод onAttach

public class yourFragment extends Fragment {
   Context context

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

Измените ваш getActivity() на getContext(). попробуйте приведенный ниже код:

Toast.makeText(getContext(), "Connection Failure", Toast.LENGTH_LONG).show();

имейте в виду, что getContext() также может возвращать null

Richard Le Mesurier 12.09.2018 09:58

Возможно, getActivity() вызывал при отсоединении фрагмента. Попытайся.

if (isAdded()) {
    Toast.makeText(getActivity(), "something", Toast.LENGTH_SHORT).show();
}
Ответ принят как подходящий

Согласно коду и javadoc для Fragment.getActivity() вы можете вернуть null:

/**
 * Return the {@link FragmentActivity} this fragment is currently associated with.
 * May return {@code null} if the fragment is associated with a {@link Context}
 * instead.
 *
 * @see #requireActivity()
 */
@Nullable
final public FragmentActivity getActivity() {
    return mHost == null ? null : (FragmentActivity) mHost.getActivity();
}

В частности, это может произойти, когда ваш фрагмент не прикреплен к действию (как указано здесь и здесь).

Точно так же getContext() также может возвращать null.

В этом, возможно, связанном сообщении есть хорошее обсуждение того, когда они могут быть нулевыми:


Простое решение уже предоставлено - поставить нулевую проверку перед отображением Toast.

Но основная проблема заключается в архитектуре - ваш код связывает активность API с вашим пользовательским интерфейсом и предполагает определенные вещи о состоянии вашего пользовательского интерфейса, то есть вы предполагаете, что когда вызов API возвращается, ваш экран все еще виден пользователю.


Лучшим решением было бы отделить вызов Retrofit от пользовательского интерфейса - поместить вызовы API в отдельный класс, не зависящий от состояния UI.

Используйте платформу событий или pub-sub для обмена данными из этого класса оболочки API с любыми компонентами пользовательского интерфейса, которым необходимо знать, когда возвращается вызов API.

EventBus или RxJava были бы двумя распространенными решениями для этого (LocalBroadcastManager был бы менее распространенным подходом).

Это позволит любому коду вызывать ваш API и подписаться на уведомление, когда API вернется.

Это также позволяет вам сохранять ваши ответы API (например) в локальной базе данных, и в этом случае вы можете просто положиться на шаблон LiveData для обновления любого пользовательского интерфейса, который должен быть.

Вот статья на Medium, в которой дается краткое описание того, как использовать компоненты архитектуры Android таким образом, используя шаблон Repository.


Учитывая, что некоторые проекты нельзя изменить сразу, могут потребоваться обходные пути.

Вышеупомянутый обходной путь с нулевой проверкой полезен тем, что приложение больше не будет аварийно завершать работу. К сожалению, это означает, что пользователь не будет предупрежден о неудачном вызове API.

Одна из альтернатив - создать свой собственный подкласс Application (многие проекты уже сделали это для инициализации общих библиотек) и предоставить метод статического доступа к этому приложению Context. (Аналогичное предположение впоследствии было сделано Кушалом.)

Затем вы можете выбрать отображение Toast с помощью приложения Context вместо приложения из фрагмента. Вы можете потерять какой-либо конкретный стиль, который был бы получен из более конкретного контекста, но преимущество будет в том, что ваш пользователь все равно сможет видеть сообщение Toast.

Представление вашего Application как синглтона было очень хорошо описано в этом посте:

спасибо за столь подробное объяснение. Я мог бы рассказать о причинах сбоя / ANR, прочитав его. В настоящий момент архитектурные изменения могут быть невозможны. Я сохраню это вместе с вашими предложениями на будущее.

Bharat Kumar 12.09.2018 10:07

100% понимают сложность или реорганизацию существующего кода, и поэтому я специально связался с другими ответами - у меня много кода, который выполняет эту простую проверку if (x != null){}, но кажется распространенным недоразумением, что getActivity() / getContext() всегда доступны, поэтому я подумал подробный ответ на этот тип вопросов может быть полезен будущим читателям.

Richard Le Mesurier 12.09.2018 10:11

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

Richard Le Mesurier 12.09.2018 10:26
if (isAdded()) {
    Toast.makeText(getActivity(), "something", Toast.LENGTH_SHORT).show();
}

или попробуйте это

if (getActivity() != null)
   Toast.makeText(getActivity(), "Connection Failure", Toast.LENGTH_LONG).show();

В моем случае оба будут работать нормально, потому что в некоторых случаях getActivity() вызывается при отсоединении фрагмента.

Так что мы должны позаботиться и об этом.

Другие вопросы по теме