19

Chúng tôi có trên ứng dụng của chúng tôi một ViewPager với một FragmentPagerAdapter trong đó có ba mảnh. Hai trong số những mảnh này được tạo thành với một Recyclerview cho mỗi mảnh.NullPointerException trên ViewPager với Recyclerview

Trang đầu tiên (đoạn không có ViewPager) được hiển thị chính xác. Tuy nhiên, khi ViewPager cố gắng pre-load trang tiếp theo (một RecyclerView), các tai nạn ứng dụng vì một NullPointerException với nhật ký sau đây:

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) 

Đây là ViewPager được khai báo như thế nào:

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); 

và 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); 
    } 
} 

Như mã từ cả hai RecyclerView dài và khác nhau cho mỗi trang tôi không thực sự biết được một phần là có liên quan vì vậy tôi sẽ không từ bỏ bất kỳ mẫu nào. Đừng ngại hỏi một phần cụ thể nếu bạn nghĩ rằng có thể hữu ích để khắc phục vấn đề.

Một điều mà tôi có thể nói với bạn là nếu tôi muốn nó hoạt động, tôi phải nhận xét cuộc gọi cho từng số setAdapter từ cả hai RecylerView.

EDIT: Đây là mã cho trang thứ hai.

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); 
      } 
     } 
    } 
} 

Bất kỳ trợ giúp nào được đánh giá cao.

+0

có bất kỳ recyclerView trong đoạn thứ ba? [CHỈNH SỬA] xin lỗi, ở đó.Có thể bạn đăng mã của đoạn thứ 2 của bạn –

+0

Trang đầu tiên là một đoạn không có bất kỳ RecyclerView nào. Tuy nhiên, có, phần thứ hai và thứ ba là các mảnh được tạo thành với một RecyclerView cho mỗi một. – Neeeko

+0

Bạn có thể đăng phương thức 'onBindViewHolder()' của bộ điều hợp không? – Rami

Trả lời

18

Tôi gặp lỗi này trong quá trình phát triển của mình. Bạn đã kiểm tra xem RecyclerView của bạn trong các tệp XML của bạn có được gói chính xác vào một bố cục khác như FrameLayout không?

Nếu không, thiết bị sẽ chỉ gặp sự cố trên Chế độ xem không phải trên chế độ xem từng đoạn.

+2

Bạn nói đúng! Bố trí của tôi chỉ gồm RecyclerView, tôi không biết rằng nó phải được bọc trong một cái khác. Cảm ơn đã giúp đỡ ! – Neeeko

+0

Bingo; cảm ơn rất nhiều, Ligol. –

+0

THANK YOU SOOOO MUCH !! –

-2

Thay đổi:

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

tới:

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

biến cuối cùng sẽ không mất bất kỳ giá trị, ngay cả khi bạn cố gắng để thêm chúng.

+0

Tôi đã thử giải pháp của bạn và vẫn có NPE. :/ – Neeeko

+0

Ồ. Sau đó, thay vì thêm từng cái một, bạn có thể gửi danh sách đầy đủ tới Bộ điều hợp và thêm tất cả vào danh sách trong bộ điều hợp. –

+3

Đó không phải là cách "biến cuối cùng" hoạt động. Bạn có thể thêm và xóa các mục khỏi danh sách ngay cả khi nó được khai báo cuối cùng. –

4

Điều này xảy ra khi bạn vô tình thêm lượt xem trực tiếp vào RecyclerView. Trong trường hợp của tôi, tôi đã sử dụng View.inflate để có bố cục trang trí với thông số RecyclerView làm thông số gốc tự động đính kèm. RecyclerView lặp lại trên bất kỳ trẻ em nào gắn với nó và hy vọng tất cả các trẻ em của nó sẽ có ViewHolders trong thông số bố cục và sẽ ném NPE này khi người giữ chế độ xem của trẻ bị thiếu.

0

Điều này xảy ra khi bạn thêm yếu tố trực thuộc listView hoặc RecyclerView trong xml bố trí tập tin của bạn.

<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> 

Ở đây tôi đã thêm một TextView bên RecyclerView mà sẽ ném tôi onLayout error (do NullPointerException) .Bạn không nên thêm các yếu tố trực thuộc RecyclerView hoặc listView.

0

Thêm không có con trong giao diện tái chế và thiết lập attachToRoot, tham số thứ ba của inflate() phương pháp để false trong khi lạm phát cách bố trí tùy chỉnh làm việc cho tôi.

@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> 
Các vấn đề liên quan