Android中SimpleCursorAdapter的bindView()方法滚动时工作原理咨询
嘿,作为Android新手能把可滚动的ListView跑起来已经超棒了!我来帮你拆解一下bindView()在列表滚动时的工作机制,顺便聊聊你代码里可以优化的地方~
先搞懂
bindView()的核心职责 首先得明白ListView的视图复用机制:当你滚动列表时,屏幕外的item不会被销毁,而是会被系统回收,用来显示刚进入屏幕的新item——这个被回收的view就是传给bindView()的那个view参数。
而bindView()的唯一任务,就是把当前Cursor指向的数据,绑定到这个复用(或新建)的view上。它不会创建新view,只负责“填数据”,这也是ListView滚动流畅的关键所在。
结合你的代码看滚动时的执行流程
先把你的代码贴出来方便分析:
@Override public void bindView(View view, Context context, Cursor cursor) { super.bindView(view, context, cursor); ViewHolder holder = (ViewHolder) view.getTag(); if (holder == null) { holder = new ViewHolder(); holder.colImp = cursor.getColumnIndexOrThrow(RemindersDbAdapter.COL_IMPORTANT); holder.listTab = view.findViewById(R.id.row_tab); view.setTag(holder); } if (cursor.getInt(holder.colImp) > 0) { holder.listTab.setBackgroundColor(context.getResources().getColor(R.color.orange)); } else { holder.listTab.setBackgroundColor(context.getResources().getColor(R.color.green)); } } static class ViewHolder { //store the column index int colImp; //store the view View listTab; }
咱们一步步看滚动时发生了什么:
- 第一次加载列表:每个item都是全新的,
view.getTag()会返回null,所以会创建ViewHolder,绑定列索引和view引用,再把ViewHolder设置为view的tag,最后绑定数据(设置背景色)。 - 开始滚动列表:比如第一个item滑出屏幕,系统把这个item的view回收,传给下一个要显示的item的
bindView()。这时候view.getTag()已经有之前设置的ViewHolder了,所以跳过null判断的分支,直接用已有的ViewHolder,把当前Cursor对应的数据(新item的colImp值)绑定到view上,设置对应的背景色。
你的代码里的小优化点(重要!)
你把ViewHolder的初始化逻辑放在bindView()里了,虽然功能没问题,但其实不是最佳实践。因为bindView()会被频繁调用(每次复用view都会触发),而newView()只会在需要创建新view的时候调用一次。
正确的做法是把ViewHolder的初始化移到newView()方法里,这样逻辑更清晰,也避免了重复的null判断:
@Override public View newView(Context context, Cursor cursor, ViewGroup parent) { // 这里创建新的item view View view = LayoutInflater.from(context).inflate(R.layout.your_item_layout, parent, false); // 初始化ViewHolder并绑定到view上 ViewHolder holder = new ViewHolder(); holder.colImp = cursor.getColumnIndexOrThrow(RemindersDbAdapter.COL_IMPORTANT); holder.listTab = view.findViewById(R.id.row_tab); view.setTag(holder); return view; } @Override public void bindView(View view, Context context, Cursor cursor) { super.bindView(view, context, cursor); // 直接获取已绑定的ViewHolder,不用再判断null ViewHolder holder = (ViewHolder) view.getTag(); // 绑定当前数据到view上 if (cursor.getInt(holder.colImp) > 0) { holder.listTab.setBackgroundColor(context.getResources().getColor(R.color.orange)); } else { holder.listTab.setBackgroundColor(context.getResources().getColor(R.color.green)); } } static class ViewHolder { int colImp; View listTab; }
滚动时的完整流程总结
再帮你梳理一遍整个流程,加深理解:
- 当列表滚动,新item要进入屏幕时,系统先检查有没有可复用的view(滑出屏幕的item的view)。
- 如果有复用view,直接把这个view传给
bindView(),同时将Cursor移动到对应新item的数据位置。 bindView()通过view.getTag()拿到已绑定的ViewHolder,直接用ViewHolder里的view引用,把当前Cursor的数据绑定上去(比如设置背景色)。- 如果没有可复用的view,系统会调用
newView()创建新view,初始化ViewHolder并绑定到view上,再调用bindView()绑定数据。
这样的复用机制,避免了频繁创建新view和重复调用findViewById(),能大幅提升列表滚动的流畅度~
内容的提问来源于stack exchange,提问作者Pubudu Mahesh Meththananda
相关产品推荐
相关产品推荐

