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
или же 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
в прикрепленных фрагментах до сих пор хранится:
Убедитесь, что ваш фрагмент не отделен, проверив
isDetached()
первый.То, что я в конечном итоге делал сам: уже была обертка для создания шаблонов Builder для
Snackbar
в кодовой базе, поэтому я раздвоилfindSuitableParent()
в построителе и добавил проверку, чтобы увидеть, что это возвращает!= null
прежде чем пытаться позвонитьSnackbar.make()
, Таким образом, вызывающим абонентам Snackbar не нужно было добавлять какие-либо дополнительные проверки.
По процессу, закусочная ищет вид.
- Вы использовали вид фрагментов
- Но само представление фрагмента еще не прикреплено, так как onAttach фрагмента еще не вызывается.
Таким образом, само приложение на самом деле не знает, во время выполнения, что вы на самом деле ссылались на представление фрагмента.
Попробуйте разместить метод снэк-бара в "onResume" фрагмента. Надеюсь это поможет.
Почему вы делаете это в onCreate?
Дополнительно убедитесь, что вы следуете нескольким правилам:
- Убедитесь, что ваша основная активность наследует от AppCompatActivity, поскольку это необходимо для использования библиотек поддержки.
- Убедитесь, что представление, которое вы передаете, действительно существует (вот почему я спрашиваю, почему вы делаете это в onCreate, а почему не после?)
Как сказано в документации, "Snackbar попытается найти родительское представление, чтобы сохранить представление Snackbar от значения, данного для представления".
Таким образом, вы можете передать любой вид, который прикреплен в данный момент.