简体   繁体   中英

Android Snackbar NullPointerException in Fragment

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:

  1. Make sure your fragment is not detached by checking isDetached() first.

  2. 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:

  1. Ensure that your main Activity inherits from AppCompatActivity as that is necessary for using the Support libs.
  2. 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM