I want to add a basic snackbar to my application but i have received an error that i couldn't figure out why.
I added this code in the onCreateView() method in my Fragment.
Snackbar.make(view, "Snackbar", Snackbar.LENGTH_LONG)
.setAction("Action", null).show();
And received this error:
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)
...
If your Fragment is added to existing activity(Remember you can add it through xml), you should call the SnackBar's method into the onActivityCreated() method of the Fragment.
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
Snackbar.make(view, "Snackbar", Snackbar.LENGTH_LONG)
.setAction("Action", null).show();
}
1.move it to onActivityCreated method.
2.try to use getView() in make method like following:
Snackbar.make(getView(), "Snackbar", Snackbar.LENGTH_LONG)
.setAction("Action", null).show();
In a codebase I was working on, there were Snackbar
s shown in asynchronous method callbacks such as error handlers of a network call. When the Snackbar
was being made, the Fragment
it was going to go was no longer attached and its View
as returned by getView()
did not have a CoordinatorLayout
or FrameLayout
Snackbar
wants to have in the view's hierarchy.
In particular, it's the private findSuitableParent()
method in Snackbar
that traverses the hierarchy:
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;
}
The result of this method is passed to Snackbar
constructor that calls getContext()
on it, and if this method returns null
you get the NPE as seen in the question.
There are a couple of ways to fix the problem, assuming the happy case of having a CoordinatorLayout
or FrameLayout
in attached fragments still holds:
Make sure your fragment is not detached by checking isDetached()
first.
What I ended up doing myself: There was already a Builder pattern styling wrapper for the Snackbar
in the codebase, so I forked the findSuitableParent()
in the builder and added a check to see it returns != null
before attempting to call Snackbar.make()
. This way the Snackbar builder callers did not have to add any additional checks.
By process, the snack bar searches for the view.
- You used the fragments view
- But the fragment view itself is not yet attached, since onAttach of the
fragment is not yet called.
So the app itself doesn't really know, on runtime, that you were actually referring to the view of the fragment.
Try placing your snackbar show method at the "onResume" of the fragment.
Hope this helps.
Why are you doing this within onCreate?
Additionally make sure that you are following a couple of rules:
- Ensure that your main Activity inherits from AppCompatActivity as that is necessary for using the Support libs.
- Ensure that the view that you are passing actually exists (this is why I'm asking why you're doing this in onCreate and why not after?)
As the documentation says "Snackbar will try and find a parent view to hold Snackbar's view from the value given to view".
So you can pass any view that is attached at the moment.