Android开发笔记:RecyclerView.addView()导致NullPointerException

背景

最近想实现一个控件漂浮在Item上的效果,需要随着List滑动改变漂浮控件的位置。效果如下图:
Android开发笔记:RecyclerView.addView()导致NullPointerException_第1张图片

本文地址:https://blog.csdn.net/Xiong_IT
作者:MichaelX

最开始的2种方案

  1. 利用Window.addView(),滑动时updatePosition
  2. 利用RecyclerView.addView(),滑动时改变漂浮控件floatView的layoutParams.margin

第一种,利用Window更新位置稍微复杂点,放弃。
第二种,RecyclerView.addView()报错。

java.lang.NullPointerException: Attempt to invoke virtual method 'boolean android.support.v7.widget.RecyclerView$ViewHolder.shouldIgnore()' on a null object reference
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2876)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2941)
        at android.app.ActivityThread.-wrap12(ActivityThread.java)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1645)
        at android.os.Handler.dispatchMessage(Handler.java:110)
        at android.os.Looper.loop(Looper.java:203)
        at android.app.ActivityThread.main(ActivityThread.java:6455)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1134)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:995)
     Caused by: 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$LayoutManager.removeAndRecycleAllViews(RecyclerView.java:9697)
        at android.support.v7.widget.RecyclerView.removeAndRecycleViews(RecyclerView.java:1068)
        at android.support.v7.widget.RecyclerView.setAdapterInternal(RecyclerView.java:1091)
        at android.support.v7.widget.RecyclerView.setAdapter(RecyclerView.java:1051)

重点:
Attempt to invoke virtual method 'boolean android.support.v7.widget.RecyclerView$ViewHolder.shouldIgnore()' on a null object reference

源码分析

从上述报错log可知,出错位置在

android.support.v7.widget.RecyclerView.setAdapter(RecyclerView.java:1051)

报错位置在

android.support.v7.widget.RecyclerView$LayoutManager.removeAndRecycleAllViews(RecyclerView.java:9697)

removeAndRecycleAllViews函数代码如下:

public void removeAndRecycleAllViews(Recycler recycler) {
            for (int i = getChildCount() - 1; i >= 0; i--) {
                final View view = getChildAt(i);
                if (!getChildViewHolderInt(view).shouldIgnore()) {
                    removeAndRecycleViewAt(i, recycler);
                }
            }
 }

当RecyclerView.addView之后,会进入for循环,走到getChildViewHolderInt(view)函数中,

static ViewHolder getChildViewHolderInt(View child) {
        if (child == null) {
            return null;
        }
        return ((LayoutParams) child.getLayoutParams()).mViewHolder;
    }

我们知道,floatView是直接添加的,它并没有mViewHolder,所以这一步返回值为null,所以导致错误:

java.lang.NullPointerException: Attempt to invoke virtual method 'boolean android.support.v7.widget.RecyclerView$ViewHolder.shouldIgnore()' on a null object reference

最后解决

利用RecyclerView的父控件来添加漂浮控件floatView,滑动监听和更新位置的逻辑不变。
如果刚好碰到这样问题的同学也可以试试给floatView设置ViewHolder,/手动滑稽

((ViewGroup)(mRecyclerView.getParent())).addView(floatView);

你可能感兴趣的:(Android)