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)
...
Ответы
Ответ 1
Если ваш фрагмент добавлен к существующей активности (помните, вы можете добавить его через xml), вы должны вызвать метод SnackBar в метод onActivityCreated() фрагмента.
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
Snackbar.make(view, "Snackbar", Snackbar.LENGTH_LONG)
.setAction("Action", null).show();
}
Ответ 2
1. Подключите его к методу onActivityCreated.
2.Попробуйте использовать getView() в методе make следующим образом:
Snackbar.make(getView(), "Snackbar", Snackbar.LENGTH_LONG)
.setAction("Action", null).show();
Ответ 3
В кодовой базе, над которой я работал, в асинхронных обратных вызовах были указаны 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 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
в прикрепленных фрагментах сохраняется:
-
Убедитесь, что ваш фрагмент не отсоединен, сначала проверив isDetached()
.
-
Что я в итоге сделал сам: в кодовой базе уже был шаблон Builder для Snackbar
Я разветкил findSuitableParent()
в построителе и добавил чек, чтобы увидеть, как он возвращает != null
, прежде чем пытаться позвонить Snackbar.make()
. Таким образом, вызывающим абонентам Snackbar не нужно было добавлять дополнительные проверки.
Ответ 4
По ходу процесса снэк-бар ищет представление.
- Вы использовали представление фрагментов
- Но сам фрагмент не привязан, так как onAttach
фрагмент еще не вызван.
Таким образом, само приложение не знает, во время выполнения, что вы на самом деле ссылаетесь на представление фрагмента.
Попробуйте разместить метод show snackbar в "onResume" фрагмента.
Надеюсь, это поможет.
Ответ 5
Почему вы делаете это внутри onCreate?
Кроме того, убедитесь, что вы выполняете несколько правил:
- Убедитесь, что ваша основная активность наследуется от AppCompatActivity, которая необходима для использования файлов поддержки.
- Убедитесь, что представление, которое вы передаете, фактически существует (вот почему я спрашиваю, почему вы делаете это в onCreate и почему не после?)
Ответ 6
Как говорится в документации, "Snackbar попытается найти родительское представление, чтобы сохранить представление Snackbar из значения, данного для просмотра".
Таким образом, вы можете передать любое представление, которое подключено в данный момент.