Intereting Posts

Android Snackbar NullPointerException в фрагменте

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

Я добавил этот код в метод onCreateView () в своем фрагменте.

Snackbar.make(view, "Snackbar", Snackbar.LENGTH_LONG) .setAction("Action", null).show(); 

И получил эту ошибку:

 06-01 10:26:09.955 1232-1232/? E/ActivityThread﹕ Failed to find provider info for me.muraterdogan.watchme.MetricaContentProvider 06-01 10:26:10.075 1232-1447/? E/ActivityThread﹕ Failed to find provider info for me.muraterdogan.watchme.YPLContentProvider 06-01 10:33:55.044 6646-6646/? E/AndroidRuntime﹕ FATAL EXCEPTION: main Process: me.muraterdogan.watchme, PID: 6646 java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.Context android.view.ViewGroup.getContext()' on a null object reference at android.support.design.widget.Snackbar.<init>(Snackbar.java:116) at android.support.design.widget.Snackbar.make(Snackbar.java:140) at me.muraterdogan.watchme.fragments.TrendingFragment.GetData(TrendingFragment.java:90) at me.muraterdogan.watchme.fragments.TrendingFragment.onCreateView(TrendingFragment.java:83) ... 

Если ваш фрагмент добавлен к существующей активности (помните, вы можете добавить его через xml), вы должны вызвать метод SnackBar в методе onActivityCreated () фрагмента.

 @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); Snackbar.make(view, "Snackbar", Snackbar.LENGTH_LONG) .setAction("Action", null).show(); } 

1. Переместите его в метод onActivityCreated.

2.Попробуйте использовать getView () в make как:

 Snackbar.make(getView(), "Snackbar", Snackbar.LENGTH_LONG) .setAction("Action", null).show(); 

В кодовой базе, над которой я работал, были Snackbar s в асинхронных обратных Snackbar метода, таких как обработчики ошибок сетевого вызова. Когда была сделана Snackbar , Fragment он собирался уйти, больше не привязан, и его View возвращенный getView() , не имел CoordinatorLayout или FrameLayout Snackbar хочет иметь в иерархии представления.

В частности, это частный findSuitableParent() в Snackbar который пересекает иерархию:

 private static ViewGroup findSuitableParent(View view) { ViewGroup fallback = null; do { if (view instanceof CoordinatorLayout) { // We've found a CoordinatorLayout, use it return (ViewGroup) view; } else if (view instanceof FrameLayout) { if (view.getId() == android.R.id.content) { // If we've hit the decor content view, then we didn't find a CoL in the // hierarchy, so use it. return (ViewGroup) view; } else { // It's not the content view but we'll use it as our fallback fallback = (ViewGroup) view; } } if (view != null) { // Else, we will loop and crawl up the view hierarchy and try to find a parent final ViewParent parent = view.getParent(); view = parent instanceof View ? (View) parent : null; } } while (view != null); // If we reach here then we didn't find a CoL or a suitable content view so we'll fallback return fallback; } 

Результат этого метода передается конструктору Snackbar который вызывает на нем getContext() , и если этот метод возвращает null вы получаете NPE, как показано в вопросе.

Есть несколько способов устранить проблему, предполагая, что счастливый случай наличия CoordinatorLayout или FrameLayout в прикрепленных фрагментах сохраняется:

  1. Убедитесь, что ваш фрагмент не отсоединен, isDetached() проверив isDetached() .

  2. То, что я закончил тем, что сделал сам: уже существовала оболочка шаблона шаблона Builder для Snackbar в базе кода, поэтому я findSuitableParent() в построителе и добавил чек, чтобы увидеть, что он возвращает != null Snackbar.make() прежде чем пытаться вызвать Snackbar.make() . Таким образом, вызывающим абонентам Snackbar не нужно было добавлять дополнительные проверки.

По ходу процесса снэк-бар ищет представление.

  • Вы использовали представление фрагментов
  • Но сам фрагмент не привязан, так как onAttach фрагмента еще не вызван.

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

Попробуйте разместить свой метод snackbar show на «onResume» фрагмента. Надеюсь это поможет.

Почему вы делаете это в onCreate?

Кроме того, убедитесь, что вы выполняете несколько правил:

  1. Убедитесь, что ваша основная активность наследуется от AppCompatActivity, что необходимо для использования файлов поддержки.
  2. Убедитесь, что представление, которое вы передаете, фактически существует (вот почему я спрашиваю, почему вы делаете это в onCreate и почему не после?)

Как говорится в документации, «Snackbar попытается найти родительское представление, чтобы удерживать представление Snackbar от значения, данного для просмотра».

Таким образом, вы можете передать любое представление, которое прилагается в данный момент.