Я получаю ошибки на нескольких устройствах, когда пытаюсь отобразить тост внутри фрагментов. этот тост обычно связан с ошибкой реакции на модернизацию. код тоста прост. Пожалуйста, предложите, не мог найти причины, ища здесь и там.
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)
Привет, Сайед Даниш Хайдер. спасибо за ваш ответ ... не могли бы вы помочь мне разобраться с небольшим объяснением вашего предложения ....
Я отправил ответ для справки, примите мой ответ, если он полезен
Сохраните контекст приложения в глобальной переменной и используйте эту глобальную переменную вместо getActivity ()
@Kushal Мне это нравится - мы, должно быть, думаем одинаково. Я добавлял это в свой ответ примерно в то же время, когда вы это разместили. Я также включил ссылку на код, в котором это делается с использованием шаблона Singleton. Может быть, не во всех случаях, но это отличный способ решения таких сложных случаев.




Ваша активность 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
Возможно, 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 для обновления любого пользовательского интерфейса, который должен быть.
Учитывая, что некоторые проекты нельзя изменить сразу, могут потребоваться обходные пути.
Вышеупомянутый обходной путь с нулевой проверкой полезен тем, что приложение больше не будет аварийно завершать работу. К сожалению, это означает, что пользователь не будет предупрежден о неудачном вызове API.
Одна из альтернатив - создать свой собственный подкласс Application (многие проекты уже сделали это для инициализации общих библиотек) и предоставить метод статического доступа к этому приложению Context. (Аналогичное предположение впоследствии было сделано Кушалом.)
Затем вы можете выбрать отображение Toast с помощью приложения Context вместо приложения из фрагмента. Вы можете потерять какой-либо конкретный стиль, который был бы получен из более конкретного контекста, но преимущество будет в том, что ваш пользователь все равно сможет видеть сообщение Toast.
Представление вашего Application как синглтона было очень хорошо описано в этом посте:
спасибо за столь подробное объяснение. Я мог бы рассказать о причинах сбоя / ANR, прочитав его. В настоящий момент архитектурные изменения могут быть невозможны. Я сохраню это вместе с вашими предложениями на будущее.
100% понимают сложность или реорганизацию существующего кода, и поэтому я специально связался с другими ответами - у меня много кода, который выполняет эту простую проверку if (x != null){}, но кажется распространенным недоразумением, что getActivity() / getContext() всегда доступны, поэтому я подумал подробный ответ на этот тип вопросов может быть полезен будущим читателям.
@BharatKumar Я добавил еще один обходной путь, чтобы вы по-прежнему могли отображать тост для пользователя с помощью контекста приложения - это может быть более полезно, чем вообще ничего не отображать.
if (isAdded()) {
Toast.makeText(getActivity(), "something", Toast.LENGTH_SHORT).show();
}
или попробуйте это
if (getActivity() != null)
Toast.makeText(getActivity(), "Connection Failure", Toast.LENGTH_LONG).show();
В моем случае оба будут работать нормально, потому что в некоторых случаях getActivity() вызывается при отсоединении фрагмента.
Так что мы должны позаботиться и об этом.
используйте getContext () вместо getActivity ()