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)
...

6 ответов

Решение

Если ваш фрагмент добавлен к существующему действию (помните, что вы можете добавить его через 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 Отображается в асинхронных обратных вызовах методов, таких как обработчики ошибок сетевого вызова. Когда Snackbar было сделано, Fragment он собирался идти больше не был привязан и его View как возвращено getView() не было CoordinatorLayout или же FrameLayoutSnackbar хочет иметь в иерархии представления.

В частности, это частный 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() первый.

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

По процессу, закусочная ищет вид.

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

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

Попробуйте разместить метод снэк-бара в "onResume" фрагмента. Надеюсь это поможет.

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

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

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

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

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

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