web-dev-qa-db-de.com

NullPointerException bei ViewPager mit Recyclerview

Wir haben auf unserer App einen ViewPager mit einer FragmentPagerAdapter, die drei Fragmente enthält. Zwei dieser Fragmente bestehen aus einem Recyclerview für jedes.

Die erste Seite (das Fragment ohne ViewPager) wird korrekt angezeigt. Wenn der ViewPager jedoch versucht, die nächste Seite (eine RecyclerView) vorzuladen, stürzt die App aufgrund einer NullPointerException mit dem folgenden Protokoll ab:

 Java.lang.NullPointerException: Attempt to invoke virtual method 'boolean Android.support.v7.widget.RecyclerView$ViewHolder.shouldIgnore()' on a null object reference
         at Android.support.v7.widget.RecyclerView.findMinMaxChildLayoutPositions(RecyclerView.Java:2839)
         at Android.support.v7.widget.RecyclerView.dispatchLayout(RecyclerView.Java:2626)
         at Android.support.v7.widget.RecyclerView.onLayout(RecyclerView.Java:3011)
         at Android.view.View.layout(View.Java:15684)
         at Android.view.ViewGroup.layout(ViewGroup.Java:4981)
         at Android.support.v4.view.ViewPager.onLayout(ViewPager.Java:1626)
         at Android.view.View.layout(View.Java:15684)
         at Android.view.ViewGroup.layout(ViewGroup.Java:4981)
         at Android.widget.FrameLayout.layoutChildren(FrameLayout.Java:573)
         at Android.widget.FrameLayout.onLayout(FrameLayout.Java:508)
         at Android.view.View.layout(View.Java:15684)
         at Android.view.ViewGroup.layout(ViewGroup.Java:4981)
         at Android.widget.LinearLayout.setChildFrame(LinearLayout.Java:1703)
         at Android.widget.LinearLayout.layoutVertical(LinearLayout.Java:1557)
         at Android.widget.LinearLayout.onLayout(LinearLayout.Java:1466)
         at Android.view.View.layout(View.Java:15684)
         at Android.view.ViewGroup.layout(ViewGroup.Java:4981)
         at Android.support.design.widget.CoordinatorLayout.layoutChild(CoordinatorLayout.Java:1000)
         at Android.support.design.widget.CoordinatorLayout.onLayoutChild(CoordinatorLayout.Java:710)
         at Android.support.design.widget.CoordinatorLayout.onLayout(CoordinatorLayout.Java:724)
         at Android.view.View.layout(View.Java:15684)
         at Android.view.ViewGroup.layout(ViewGroup.Java:4981)
         at Android.support.v4.widget.DrawerLayout.onLayout(DrawerLayout.Java:907)
         at Android.view.View.layout(View.Java:15684)
         at Android.view.ViewGroup.layout(ViewGroup.Java:4981)
         at Android.widget.FrameLayout.layoutChildren(FrameLayout.Java:573)
         at Android.widget.FrameLayout.onLayout(FrameLayout.Java:508)
         at Android.view.View.layout(View.Java:15684)
         at Android.view.ViewGroup.layout(ViewGroup.Java:4981)
         at Android.widget.LinearLayout.setChildFrame(LinearLayout.Java:1703)
         at Android.widget.LinearLayout.layoutVertical(LinearLayout.Java:1557)
         at Android.widget.LinearLayout.onLayout(LinearLayout.Java:1466)
         at Android.view.View.layout(View.Java:15684)
         at Android.view.ViewGroup.layout(ViewGroup.Java:4981)
         at Android.widget.FrameLayout.layoutChildren(FrameLayout.Java:573)
         at Android.widget.FrameLayout.onLayout(FrameLayout.Java:508)
         at Android.view.View.layout(View.Java:15684)
         at Android.view.ViewGroup.layout(ViewGroup.Java:4981)
         at Android.widget.LinearLayout.setChildFrame(LinearLayout.Java:1703)
         at Android.widget.LinearLayout.layoutVertical(LinearLayout.Java:1557)
         at Android.widget.LinearLayout.onLayout(LinearLayout.Java:1466)
         at Android.view.View.layout(View.Java:15684)
         at Android.view.ViewGroup.layout(ViewGroup.Java:4981)
         at Android.widget.FrameLayout.layoutChildren(FrameLayout.Java:573)
         at Android.widget.FrameLayout.onLayout(FrameLayout.Java:508)
         at Android.view.View.layout(View.Java:15684)
         at Android.view.ViewGroup.layout(ViewGroup.Java:4981)
         at Android.view.ViewRootImpl.performLayout(ViewRootImpl.Java:2186)
         at Android.view.ViewRootImpl.performTraversals(ViewRootImpl.Java:1920)
         at Android.view.ViewRootImpl.doTraversal(ViewRootImpl.Java:1106)
         at Android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.Java:6018)
         at Android.view.Choreographer$CallbackRecord.run(Choreographer.Java:792)
         at Android.view.Choreographer.doCallbacks(Choreographer.Java:596)
         at Android.view.Choreographer.doFrame(Choreographer.Java:557)
         at Android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.Java:778)
         at Android.os.Handler.handleCallback(Handler.Java:739)
         at Android.os.Handler.dispatchMessage(Handler.Java:95)
         at Android.os.Looper.loop(Looper.Java:155)
         at Android.app.ActivityThread.main(ActivityThread.Java:5696)
         at Java.lang.reflect.Method.invoke(Native Method)
         at Java.lang.reflect.Method.invoke(Method.Java:372)

So wird der ViewPager deklariert:

ViewPager viewPager = (ViewPager) findViewById(R.id.viewpager);
ViewPagerAdapter adapter = new ViewPagerAdapter(getSupportFragmentManager());
adapter.addFrag(fragment1, "fragment1");
adapter.addFrag(fragment2, "fragment2");
adapter.addFrag(fragment3, "fragment3");
viewPager.setAdapter(adapter);

Und der Adapter:

    private class ViewPagerAdapter extends FragmentPagerAdapter {
    private final List<Fragment> mFragmentList = new ArrayList<>();
    private final List<String> mFragmentTitleList = new ArrayList<>();
    public ViewPagerAdapter(FragmentManager manager) {
        super(manager);
    }
    @Override
    public Fragment getItem(int position) {
        return mFragmentList.get(position);
    }
    @Override
    public int getCount() {
        return mFragmentList.size();
    }
    public void addFrag(Fragment fragment, String title) {
        mFragmentList.add(fragment);
        mFragmentTitleList.add(title);
    }
    @Override
    public CharSequence getPageTitle(int position) {
        return mFragmentTitleList.get(position);
    }
}

Da der Code aus beiden RecyclerView-Dateien lang ist und für jede Seite unterschiedlich ist, weiß ich nicht wirklich, welcher Teil relevant ist, daher gebe ich keine Probe. Zögern Sie nicht, nach einem bestimmten Teil zu fragen, wenn Sie der Meinung sind, dass es hilfreich sein kann, das Problem zu beheben.

Eine Sache, die ich Ihnen sagen kann, ist, dass ich, wenn ich will, dass es funktioniert, den Aufruf für jede der setAdapter von beiden RecylerView kommentieren muss.

EDIT: Hier ist der Code für die zweite Seite.

public class MyFragment extends Fragment {

    RecyclerView recyclerView;
    GridAdapter gridAdapter;

    public GridAdapter getGridAdapter() {
        return gridAdapter;
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        final View v = inflater.inflate(R.layout.our_layout, container, false);
        recyclerView = (RecyclerView) v.findViewById(R.id.recycler_view);
        gridLayoutManager.setSmoothScrollbarEnabled(true);
        recyclerView.setLayoutManager(gridLayoutManager);

        recyclerView.setHasFixedSize(true);

        return v;
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        ArrayList<Model> model = getArguments().getParcelableArrayList("extra");
        if (model != null && model.size() != 0) {
            gridAdapter = new GridAdapter(model);
            recyclerView.setAdapter(gridAdapter);
        }
    }

    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);
        if (isVisibleToUser && isResumed()){
            onResume();
        }
    }

    @Override
    public void onResume() {
        super.onResume();
        if (!getUserVisibleHint())
            return;
    }

    public class GridSpacingItemDecoration extends RecyclerView.ItemDecoration {

        private int spanCount;
        private int spacingLeft;
        private int spacingRight;
        private int spacingTop;
        private int spacingBottom;
        private boolean includeEdge;

        public GridSpacingItemDecoration(int spanCount, int spacingLeft, int spacingTop, int spacingRight, int spacingBottom, boolean includeEdge) {
            this.spanCount = spanCount;
            this.spacingLeft = spacingLeft;
            this.spacingRight = spacingRight;
            this.spacingTop = spacingTop;
            this.spacingBottom = spacingBottom;
            this.includeEdge = includeEdge;
        }

        @Override
        public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
            int position = parent.getChildAdapterPosition(view); // item position
            int column = position % spanCount; // item column

            if (includeEdge) {
                outRect.left = spacingLeft - column * spacingLeft / spanCount; // spacing - column * ((1f / spanCount) * spacing)
                outRect.right = (column + 1) * spacingRight / spanCount; // (column + 1) * ((1f / spanCount) * spacing)

                if (position < spanCount) { // top Edge
                    outRect.top = spacingTop;
                }
                outRect.bottom = spacingBottom; // item bottom
            } else {
                outRect.left = column * spacingLeft / spanCount; // column * ((1f / spanCount) * spacing)
                outRect.right = spacingRight - (column + 1) * spacingRight / spanCount; // spacing - (column + 1) * ((1f /    spanCount) * spacing)
                if (position >= spanCount) {
                    outRect.top = spacingTop; // item top
                }
            }
        }
    }

    public class GridAdapter extends RecyclerView.Adapter<GridAdapter.ViewHolder> {

        private ArrayList<Model> model;

        public GridAdapter(ArrayList<Model> offer) {
            super();
            model = offer;
        }

        @Override
        public ViewHolder onCreateViewHolder(final ViewGroup parent, int viewType) {
            final View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_item, parent, false);
            final ViewHolder holder = new ViewHolder(view);
            return holder;
        }

        @Override
        public void onBindViewHolder(final ViewHolder holder, final int position) {
            final Model currentOffer = model.get(position);

            holder.category.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
                @SuppressLint("NewApi")
                @SuppressWarnings("deprecation")
                @Override
                public void onGlobalLayout() {
                    int width = holder.category.getWidth();
                    ViewGroup.LayoutParams params = holder.appIcon.getLayoutParams();
                    params.width = width;
                    params.height = width;

                    holder.appIcon.setLayoutParams(params);

                    if (Android.os.Build.VERSION.SDK_INT >= Android.os.Build.VERSION_CODES.JELLY_BEAN)
                        holder.itemView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
                    else
                        holder.itemView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
                }
            });

            Picasso.with(getActivity().getApplicationContext()).
                    load(currentOffer.getApp_logo()).fit().centerCrop().into(holder.appIcon);
            holder.appName.setText(currentOffer.getApp_name());
            holder.category.setText(currentOffer.getApp_category());

            holder.itemView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    String marketURL = AndroidTools.getPlayStoreURL(currentOffer.getApp_store_id(), true);

                    UITools.launchUrl(getActivity(), marketURL);

                }
            });

        }

        @Override
        public int getItemCount() {
            return model.size();
        }

        class ViewHolder extends RecyclerView.ViewHolder {
            private ImageView appIcon;
            private TextView appName;
            private TextView category;

            public ViewHolder(View itemView) {
                super(itemView);
                appIcon = (ImageView)itemView.findViewById(R.id.item_icon);
                appName = (TextView)itemView.findViewById(R.id.item_app_name);
                category = (TextView)itemView.findViewById(R.id.item_category);
            }
        }
    }
}

Jede Hilfe wird sehr geschätzt.

21
Neeeko

Ich habe diesen Fehler während einer meiner Entwicklung erhalten. Haben Sie überprüft, ob Ihre RecyclerView in Ihren XML-Dateien korrekt in ein anderes Layout wie ein FrameLayout eingebunden ist?

Wenn nicht, stürzt es nur auf einem Viewpager ab und nicht auf der Ansicht eines einzelnen Fragments.

20
Ligol

Dies geschieht, wenn Sie versehentlich Ansichten direkt zur RecyclerView hinzufügen. In meinem Fall habe ich View.inflate für ein Dekorateur-Layout mit der RecyclerView als übergeordneten Parameter verwendet, die ihn automatisch anfügt. RecyclerView durchläuft alle mit ihm verbundenen untergeordneten Elemente und erwartet, dass alle untergeordneten Elemente der Ansicht ViewHolders in den Layoutparametern vorhanden sind, und diese NPE wird ausgegeben, wenn der Ansichtsinhaber eines Kindes null ist.

6
visser4

Fügen Sie keine Kinder in der Recycler-Ansicht hinzu und setzen Sie attachToRoot, den dritten Parameter der inflate()-Methode auffalse, während Sie das benutzerdefinierte Layout aufblasen.

@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

    View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.online_user, parent, false);
    return new RecyclerViewHolder(view.findViewById(R.id.onlineUserView));
}

Layout:

<LinearLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
Android:layout_width="match_parent"
Android:layout_height="match_parent"
Android:orientation="vertical">

<Android.support.v7.widget.RecyclerView
    Android:id="@+id/onlineUsersView"
    Android:layout_width="match_parent"
    Android:layout_height="match_parent" />

</LinearLayout>
0
Nabin Bhandari

Dies geschieht, wenn Sie Elemente direkt unter listView oder RecyclerViewin Ihre xml Layout -Datei einfügen.

<Android.support.v7.widget.RecyclerView
Android:layout_width="match_parent"
Android:layout_height="match_parent"
Android:scrollbars="vertical">

<TextView
    Android:layout_width="match_parent"
    Android:layout_height="wrap_content" /> 

 </Android.support.v7.widget.RecyclerView>

Hier habe ich eine Textansicht in RecyclerView hinzugefügt, die mich onLayout error (verursacht durch NullPointerException) wirft. Sie sollten keine Elemente direkt unter RecyclerView oder listView hinzufügen.

0
Siva Prakash