19

Wir haben in unserer App eine ViewPager mit einer FragmentPagerAdapter, die drei Fragmente enthält. Zwei dieser Fragmente sind mit jeweils einem Recyclerview zusammengesetzt.NullPointerException on ViewPager mit Recyclerview

Die erste Seite (das Fragment ohne ViewPager) wird korrekt angezeigt. Wenn jedoch die ViewPager zu versucht vorbelasten die nächste Seite (a RecyclerView), die App stürzt wegen eines NullPointerException mit folgendem Protokoll:

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) 

Hier ist, wie der ViewPager erklärt wird:

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 sowohl von der RecyclerView ist lang und unterschiedlich für jede Seite, die ich nicht wirklich wissen, was relevant Teil ist, damit ich nicht geben irgendeine Probe. Zögern Sie nicht, nach einem bestimmten Teil zu fragen, wenn Sie denken, dass es hilfreich sein kann, das Problem zu beheben.

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

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

+0

gibt es eine recyclerView im dritten Fragment? [EDITED] Entschuldigung, es ist dort. Sie können den Code Ihres zweiten Fragments posten –

+0

Die erste Seite ist ein Fragment ohne RecyclerView. Ja, der zweite und der dritte sind Fragmente, die für jeden einen RecyclerView enthalten. – Neeeko

+0

Können Sie Ihre 'onBindViewHolder()' Methode Ihres Adapters posten? – Rami

Antwort

18

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

Wenn nicht, wird es nur auf einem Viewpager und nicht auf Einzelfragment-Ansicht abstürzen.

+2

Sie haben Recht! Mein Layout bestand nur aus einem RecyclerView, ich wusste nicht, dass es in einen anderen eingepackt werden musste. Danke für die Hilfe ! – Neeeko

+0

Bingo; Vielen Dank, Ligol. –

+0

DANKE SOOOO VIEL !! –

-2

Wechsel:

private final List<Fragment> mFragmentList = new ArrayList<>(); 
private final List<String> mFragmentTitleList = new ArrayList<>(); 

zu:

// remove final keyword 
private List<Fragment> mFragmentList = new ArrayList<>(); 
private List<String> mFragmentTitleList = new ArrayList<>(); 

Schluss Variable keine Werte nehmen, auch wenn Sie versuchen, sie zu addieren.

+0

Ich habe versucht, Ihre Lösung und immer noch die NPE. :/ – Neeeko

+0

Oh. Dann können Sie die vollständige Liste einzeln an Adapter senden und alle zur Liste im Adapter hinzufügen. –

+3

So funktionieren "final variables" nicht. Sie können Elemente aus der Liste hinzufügen und entfernen, auch wenn sie als endgültig deklariert sind. –

4

Dies geschieht, wenn Sie versehentlich Ansichten direkt auf die RecyclerView hinzufügen. In meinem Fall verwendete ich View.inflate für ein Dekorator-Layout mit dem RecyclerView als übergeordneten Parameter, der es automatisch anfügt. RecyclerView iteriert über alle daran angehängten untergeordneten Elemente und erwartet, dass alle untergeordneten Elemente der Sicht in den Layoutparametern ViewHolders enthalten. Diese NPE wird dann ausgelöst, wenn der Ansichtshalter eines Kindes null ist.

0

Dies geschieht, wenn Sie Elemente direkt unter listView oder RecyclerView in Ihrer xml Layout Datei hinzufü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 Textview innerhalb RecyclerView hinzugefügt, die mir onLayout error werfen (verursacht durch NullPointerException) .Sie sollten keine Elemente direkt unter RecyclerView oder listView hinzuzufügen.

0

Hinzufügen keine Kinder in den Recycler Ansicht und Einstellung attachToRoot, der dritte Parameter von inflate() Methode false, während das benutzerdefinierte Layout für mich gearbeitet aufzublasen.

@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> 
Verwandte Themen