解决ListView+BaseAdapter报getImportantForAccessibility空指针异常
嘿,我帮你揪出这个空指针错误的根源啦——你遇到的NullPointerException: Attempt to invoke virtual method 'int android.view.View.getImportantForAccessibility()' on a null object reference,核心原因是你的getView()方法返回了null!ListView要求每个列表项必须返回一个有效的View实例,一旦返回null就会触发这个 accessibility 相关的报错。
咱们一步步拆解问题和修复方案:
1. LayoutInflater初始化的漏洞是元凶
看你的Adapter构造函数,只有当传入的getActivityContext不为null时才初始化inflater,但如果这个Context参数传空了,inflater就会一直是null。到了getView()里:
if(cv== null) { holder = new ViewHolder(); if(inflater != null) { cv= inflater.inflate(R.layout.rowview_commonlist_ll, parent, false); // ... 绑定控件 } // ... 设置tag }
如果inflater是null,cv就永远不会被赋值,最后return的时候就是null,直接触发错误。
怎么改?
直接用传入的Activity来获取LayoutInflater就行!Activity本身就是Context的子类,完全不需要额外传Context参数,既精简又避免空指针:
public ListViewAdapter(Activity rAct, ArrayList<HashMap<String, String>> receivedListAdapter) { listAdapter = receivedListAdapter; // 用Activity的LayoutInflater最靠谱 this.inflater = rAct.getLayoutInflater(); }
2. ViewType的配置完全错了,还浪费内存
你现在的代码:
@Override public int getViewTypeCount() { return getCount(); } @Override public int getItemViewType(int position) { return position; }
这会让ListView觉得每个列表项都是独一无二的类型,完全废掉了ViewHolder的复用机制!数据多的时候不仅内存暴涨,还可能间接引发其他奇怪的错误。
修正方案:
既然你所有列表项用的都是同一个布局R.layout.rowview_commonlist_ll,要么删掉这两个方法,要么返回正确的固定值:
@Override public int getViewTypeCount() { // 所有项都是同一种类型,返回1 return 1; } @Override public int getItemViewType(int position) { // 所有项类型一致,返回0 return 0; }
如果以后要加多种布局,再根据实际逻辑调整这两个方法,但绝对不能返回getCount()和position。
3. getView里的空判断逻辑有坑,还有类型错误
看你绑定控件的代码里,holder.img2 = (FrameLayout) cv.findViewById(R.id.imgP);但ViewHolder里定义的img2是ImageView!这会触发ClassCastException,得先把ViewHolder的类型改对:
public class ViewHolder { TextView tv1, tv2, tv3, tv4, tv5; LinearLayout ll1, ll2, llrootLayout; ImageView img1, img3, img4, img5; FrameLayout fl, img2; // 把img2改成FrameLayout类型 }
另外,你原来的cv.setTag(holder)的判断逻辑冗余,现在inflater已经不会为空了,直接调整getView的逻辑:
@Override public View getView(final int position, View cv, ViewGroup parent) { final ViewHolder holder; if(cv== null) { holder = new ViewHolder(); // 现在inflater肯定不为null,直接inflate布局 cv= inflater.inflate(R.layout.rowview_commonlist_ll, parent, false); // 绑定所有控件 holder.img1 = cv.findViewById(R.id.images); holder.tv1 = cv.findViewById(R.id.tvDate); holder.ll1 = cv.findViewById(R.id.llDummy1); holder.ll2 = cv.findViewById(R.id.llDummy2); holder.img2 = cv.findViewById(R.id.imgP); holder.img3 = cv.findViewById(R.id.images1); holder.img4 = cv.findViewById(R.id.new1); holder.img5 = cv.findViewById(R.id.imgvAR); holder.tv2 = cv.findViewById(R.id.text1); holder.tv3 = cv.findViewById(R.id.text2); holder.tv4 = cv.findViewById(R.id.text3); holder.llrootLayout = cv.findViewById(R.id.rootTxt); // 直接给cv设置tag,不用多余判断 cv.setTag(holder); } else { holder = (ViewHolder) cv.getTag(); } // 绑定数据的时候加个安全判断,避免越界 if(listAdapter != null && position < listAdapter.size()) { HashMap<String, String> item = listAdapter.get(position); // 这里写你的数据赋值逻辑,比如 holder.tv1.setText(item.get("date")); } // 列表项的点击事件处理 // ... return cv; }
最后再加个安全保障
为了避免传入的数据源为空,在构造函数里加个非空判断:
public ListViewAdapter(Activity rAct, ArrayList<HashMap<String, String>> receivedListAdapter) { // 如果数据源是空的,就初始化一个空列表,避免getCount()报错 this.listAdapter = receivedListAdapter == null ? new ArrayList<>() : receivedListAdapter; this.inflater = rAct.getLayoutInflater(); }
按照这些步骤改完,应该就能解决这个空指针问题了!
内容的提问来源于stack exchange,提问作者Ponnangan Rajumayandi

