NullPointerException en ViewPager con Recyclerview
Tenemos en nuestra aplicación un ViewPager con un FragmentPagerAdapter
que contiene tres fragmentos. Dos de estos fragmentos se componen con una Recyclerview para cada uno.
La primera página (el fragmento sin ViewPager) se muestra correctamente. Sin embargo, cuando ViewPager intenta pre-cargar la página siguiente (un RecyclerView), la aplicación se bloquea debido a una NullPointerException
con el siguiente registro:
- ¿Cómo guardar y restaurar la posición exacta de desplazamiento de RecyclerView?
- Los elementos de RecyclerView desaparecen después de cambiar entre fragmentos
- Combinar múltiples RecyclerView.Adapter para usar con RecyclerView único (Android)
- ¿Cómo desplazarse a la parte inferior de un RecyclerView? ScrollToPosition no funciona
- Optimización de RecyclerView / ListView
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)
A continuación se muestra cómo se declara ViewPager:
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);
Y el adaptador:
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); } }
Como el código de ambos RecyclerView es largo y diferente para cada página realmente no sé qué parte es relevante por lo que no daré ninguna muestra. No dude en pedir una parte específica si cree que puede ser útil para solucionar el problema.
Una cosa que puedo decir es que si quiero que funcione, tengo que comentar la llamada para cada uno de los setAdapter
de ambos de RecylerView.
EDIT : Aquí está el código para la segunda página.
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); } } } }
Cualquier ayuda es muy apreciada.
- SwipeRefreshLayout cargador no sube cuando tire hacia abajo de Android
- RecyclerView: obtenga todas las vistas / presentaciones existentes
- Población animada de RecyclerView
- ¿Qué es la contraparte de RecyclerView.Adapter de ListView.Adpater.isEnabled ()
- Problema con selector en RecycleView
- RecyclerView: ¿Cómo simular el selector de dibujo de ListView en la parte superior?
- RecyclerView horizontal con relleno inicial
- ¿Por qué CardView y RecyclerView requieren minSdkVersion L?
Tengo este error durante uno de mis desarrollos. ¿Ha comprobado que su RecyclerView en sus archivos XML está correctamente envuelto en otro diseño como un FrameLayout?
Si no, se bloqueará sólo en un Viewpager y no en la vista de fragmento único.
Esto sucede cuando agrega vistas accidentalmente al RecyclerView
. En mi caso, utilicé View.inflate
para un diseño de decorador con el RecyclerView
como parámetro principal, que automáticamente lo adjunta. RecyclerView
itera sobre cualquier niño conectado a él y espera que todos sus niños de la visión tengan ViewHolders
en los params de la disposición, y lanzará este NPE cuando el sostenedor de la opinión de un niño es nulo.
Esto sucede cuando agrega elementos directamente en listView
o RecyclerView
en su archivo de diseño xml .
<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>
Aquí he añadido un TextView dentro de RecyclerView que me lanzará onLayout error
(causado por NullPointerException
). No debe agregar elementos directamente en RecyclerView
o listView
.
No añadir a los niños en la vista del reciclador y establecer attachToRoot
, el tercer parámetro del método attachToRoot
inflate()
a false
mientras inflar el diseño personalizado funcionó para mí.
@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)); }
Diseño:
<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>
Cambio:
private final List<Fragment> mFragmentList = new ArrayList<>(); private final List<String> mFragmentTitleList = new ArrayList<>();
a:
// remove final keyword private List<Fragment> mFragmentList = new ArrayList<>(); private List<String> mFragmentTitleList = new ArrayList<>();
La variable final no tomará valores, aunque intente agregarlos.
- Incluyendo list_content en el diseño de lista para conservar la funcionalidad ListFragment
- Integración de escáner de código de barras de Android con la página web