Android RecyclerView在Google Play商店崩溃问题求助
RecyclerView首尾Item背景修改导致崩溃的解决方案
问题背景
开发中使用RecyclerView+Adapter修改首尾Item背景色,应用在Google Play商店出现崩溃,RecyclerView嵌套在NestedScrollView中,尝试网上方案未解决。
崩溃日志
Exception java.lang.NullPointerException: at com.jodaland.example.TableAdapter.onBindViewHolder (TableAdapter.java:66) at com.jodaland.example.TableAdapter.onBindViewHolder (TableAdapter.java:17) at androidx.recyclerview.widget.RecyclerView$Adapter.onBindViewHolder (RecyclerView.java:7065) at androidx.recyclerview.widget.RecyclerView$Adapter.bindViewHolder (RecyclerView.java:7107) at androidx.recyclerview.widget.RecyclerView$Recycler.tryBindViewHolderByDeadline (RecyclerView.java:6012) at androidx.recyclerview.widget.RecyclerView$Recycler.tryGetViewHolderForPositionByDeadline (RecyclerView.java:6279) at androidx.recyclerview.widget.RecyclerView$Recycler.getViewForPosition (RecyclerView.java:6118) at androidx.recyclerview.widget.RecyclerView$Recycler.getViewForPosition (RecyclerView.java:6114) at androidx.recyclerview.widget.LinearLayoutManager$LayoutState.next (LinearLayoutManager.java:2303) at androidx.recyclerview.widget.LinearLayoutManager.layoutChunk (LinearLayoutManager.java:1627) at androidx.recyclerview.widget.LinearLayoutManager.fill (LinearLayoutManager.java:1587) at androidx.recyclerview.widget.LinearLayoutManager.onLayoutChildren (LinearLayoutManager.java:665) at androidx.recyclerview.widget.RecyclerView.dispatchLayoutStep2 (RecyclerView.java:4134) at androidx.recyclerview.widget.RecyclerView.onMeasure (RecyclerView.java:3540) at android.view.View.measure (View.java:27131) at android.view.ViewGroup.measureChildWithMargins (ViewGroup.java:7951) at android.widget.LinearLayout.measureChildBeforeLayout (LinearLayout.java:1552) at android.widget.LinearLayout.measureVertical (LinearLayout.java:842) at android.widget.LinearLayout.onMeasure (LinearLayout.java:721) at android.view.View.measure (View.java:27131) at androidx.core.widget.NestedScrollView.measureChildWithMargins (NestedScrollView.java:1792) at android.widget.FrameLayout.onMeasure (FrameLayout.java:194) at androidx.core.widget.NestedScrollView.onMeasure (NestedScrollView.java:627) at android.view.View.measure (View.java:27131) at android.widget.LinearLayout.measureVertical (LinearLayout.java:995) at android.widget.LinearLayout.onMeasure (LinearLayout.java:721) at android.view.View.measure (View.java:27131) at androidx.constraintlayout.widget.ConstraintLayout$Measurer.measure (ConstraintLayout.java:811) at androidx.constraintlayout.core.widgets.ConstraintWidgetContainer.measure (ConstraintWidgetContainer.java:632) at androidx.constraintlayout.core.widgets.ConstraintWidgetContainer.layout (ConstraintWidgetContainer.java:733) at androidx.constraintlayout.core.widgets.analyzer.BasicMeasure.solveLinearSystem (BasicMeasure.java:160) at androidx.constraintlayout.core.widgets.analyzer.BasicMeasure.solverMeasure (BasicMeasure.java:291) at androidx.constraintlayout.core.widgets.ConstraintWidgetContainer.measure (ConstraintWidgetContainer.java:120) at androidx.constraintlayout.widget.ConstraintLayout.resolveSystem (ConstraintLayout.java:1594) at androidx.constraintlayout.widget.ConstraintLayout.onMeasure (ConstraintLayout.java:1708) at android.view.View.measure (View.java:27131) at android.view.ViewGroup.measureChildWithMargins (ViewGroup.java:7951) at android.widget.FrameLayout.onMeasure (FrameLayout.java:194) at androidx.appcompat.widget.ContentFrameLayout.onMeasure (ContentFrameLayout.java:145) at android.view.View.measure (View.java:27131) at android.view.ViewGroup.measureChildWithMargins (ViewGroup.java:7951) at android.widget.LinearLayout.measureChildBeforeLayout (LinearLayout.java:1552) at android.widget.LinearLayout.measureVertical (LinearLayout.java:842) at android.widget.LinearLayout.onMeasure (LinearLayout.java:721) at android.view.View.measure (View.java:27131) at android.view.ViewGroup.measureChildWithMargins (ViewGroup.java:7951) at android.widget.FrameLayout.onMeasure (FrameLayout.java:194) at android.view.View.measure (View.java:27131) at android.view.ViewGroup.measureChildWithMargins (ViewGroup.java:7951) at android.widget.LinearLayout.measureChildBeforeLayout (LinearLayout.java:1552) at android.widget.LinearLayout.measureVertical (LinearLayout.java:842) at android.widget.LinearLayout.onMeasure (LinearLayout.java:721) at android.view.View.measure (View.java:27131) at android.view.ViewGroup.measureChildWithMargins (ViewGroup.java:7951) at android.widget.FrameLayout.onMeasure (FrameLayout.java:194) at com.android.internal.policy.DecorView.onMeasure (DecorView.java:1173) at android.view.View.measure (View.java:27131) at android.view.ViewRootImpl.performMeasure (ViewRootImpl.java:4187) at android.view.ViewRootImpl.measureHierarchy (ViewRootImpl.java:2936) at android.view.ViewRootImpl.performTraversals (ViewRootImpl.java:3204) at android.view.ViewRootImpl.doTraversal (ViewRootImpl.java:2618) at android.view.ViewRootImpl$TraversalRunnable.run (ViewRootImpl.java:9971) at android.view.Choreographer$CallbackRecord.run (Choreographer.java:1010) at android.view.Choreographer.doCallbacks (Choreographer.java:809) at android.view.Choreographer.doFrame (Choreographer.java:744) at android.view.Choreographer$FrameDisplayEventReceiver.run (Choreographer.java:995) at android.os.Handler.handleCallback (Handler.java:938) at android.os.Handler.dispatchMessage (Handler.java:99) at android.os.Looper.loop (Looper.java:246) at android.app.ActivityThread.main (ActivityThread.java:8653) at java.lang.reflect.Method.invoke at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:602) at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1130)
Adapter相关代码
@Override public void onBindViewHolder(TableAdapter.ViewHolder holder, int position) { Modal m = this.modalList.get(position); if (holder.getItemViewType() == TYPE_HEAD) { int colorGreen = ContextCompat.getColor(holder.Time.getContext(),R.color.Green); holder.Time.setBackgroundColor(colorGreen); holder.Time.setText(m.getTime()); int colorGray = ContextCompat.getColor(holder.Money.getContext(),R.color.Gray); holder.Money.setBackgroundColor(colorGray); holder.Money.setText(m.getMoney()); int colorOchre = ContextCompat.getColor(holder.profit.getContext(),R.color.Ochre); holder.profit.setBackgroundColor(colorOchre); holder.profit.setText(m.getprofit()); int colorBlue = ContextCompat.getColor(holder.Sum.getContext(),R.color.Blue); holder.Sum.setBackgroundColor(colorBlue); holder.Sum.setText(m.getSum()); }else { //line 66 holder.Time.setText(m.getTime()); holder.Money.setText(m.getMoney()); holder.profit.setText(m.getprofit()); holder.Sum.setText(m.getSum()); } } @Override public int getItemCount() { int a; if (modalList != null && !modalList.isEmpty()) { a = modalList.size(); } else { a = 0; } return a; } @Override public int getItemViewType(int position) { if (position == 0 || position == modalList.size()-1 ) return TYPE_HEAD; return TYPE_LIST; } class ViewHolder extends RecyclerView.ViewHolder { public TextView Time; public TextView Money; public TextView profit; public TextView Sum; public ViewHolder(@NonNull View itemView) { super(itemView); Time = itemView.findViewById(R.id.lbl_time); Money = itemView.findViewById(R.id.lbl_money); profit = itemView.findViewById(R.id.lbl_profit); Sum = itemView.findViewById(R.id.lbl_sum); } } }
解决方案
1. 修复ViewHolder控件空指针问题
- 检查Item布局文件,确保
R.id.lbl_time、R.id.lbl_money等ID存在且拼写正确,与ViewHolder中的findViewById调用一一对应。 - 若为
TYPE_HEAD和TYPE_LIST使用了不同布局,必须在onCreateViewHolder中根据视图类型加载对应布局,否则会导致控件找不到:
@Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view; if (viewType == TYPE_HEAD) { view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_head_layout, parent, false); } else { view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_normal_layout, parent, false); } return new ViewHolder(view); }
2. 增加数据空判断
在onBindViewHolder中先判断数据是否为空,避免空对象调用方法:
@Override public void onBindViewHolder(TableAdapter.ViewHolder holder, int position) { if (modalList == null || position >= modalList.size()) { holder.Time.setText(""); holder.Money.setText(""); holder.profit.setText(""); holder.Sum.setText(""); return; } Modal m = modalList.get(position); if (m == null) { holder.Time.setText(""); holder.Money.setText(""); holder.profit.setText(""); holder.Sum.setText(""); return; } // 原有逻辑 if (holder.getItemViewType() == TYPE_HEAD) { int colorGreen = ContextCompat.getColor(holder.Time.getContext(),R.color.Green); holder.Time.setBackgroundColor(colorGreen); holder.Time.setText(m.getTime() != null ? m.getTime() : ""); int colorGray = ContextCompat.getColor(holder.Money.getContext(),R.color.Gray); holder.Money.setBackgroundColor(colorGray); holder.Money.setText(m.getMoney() != null ? m.getMoney() : ""); int colorOchre = ContextCompat.getColor(holder.profit.getContext(),R.color.Ochre); holder.profit.setBackgroundColor(colorOchre); holder.profit.setText(m.getprofit() != null ? m.getprofit() : ""); int colorBlue = ContextCompat.getColor(holder.Sum.getContext(),R.color.Blue); holder.Sum.setBackgroundColor(colorBlue); holder.Sum.setText(m.getSum() != null ? m.getSum() : ""); } else { holder.Time.setText(m.getTime() != null ? m.getTime() : ""); holder.Money.setText(m.getMoney() != null ? m.getMoney() : ""); holder.profit.setText(m.getprofit() != null ? m.getprofit() : ""); holder.Sum.setText(m.getSum() != null ? m.getSum() : ""); } }
3. 修复getItemViewType的边界判断
避免数据变化导致的position越界,增加空判断:
@Override public int getItemViewType(int position) { if (modalList == null || modalList.isEmpty()) { return TYPE_LIST; } // 确保position在合法范围内 if (position >=0 && (position == 0 || position == modalList.size() -1)) { return TYPE_HEAD; } return TYPE_LIST; }
4. 适配NestedScrollView嵌套场景
为RecyclerView的LayoutManager开启自动测量,避免嵌套导致的测量异常:
LinearLayoutManager layoutManager = new LinearLayoutManager(context); layoutManager.setAutoMeasureEnabled(true); recyclerView.setLayoutManager(layoutManager); // 设置RecyclerView高度为wrap_content recyclerView.setLayoutParams(new ViewGroup.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT ));
内容的提问来源于stack exchange,提问作者fekhreddine bouziane
相关产品推荐
相关产品推荐

