Android——listView多选的实现

Android ListView长按弹出CheckBox,实现全选,反选,批量删除功能 ListView长按弹出CheckBox,实现全选,反选,批量删除功能. 主布局:activity_main xml version="1.0" encoding="utf-8"?> RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http: 阅读详情

今天项目中遇到了一个需求,就是listView中有多选功能,能实现礼品的批量赠送。自己写完后发现,由于listView的复用问题,导致多选实现不正常。所以在查了很多的资料和看了一些高手的博客后明白了原理和解决方式。在此总结。

listView的复用问题

先说listView的复用吧,由于个人的总结与理解不是很到位,这里引用查资料过程中看到的一个解释listView复用觉得很好的博客。
参考的listview复用分析原文

listView复用原理图

由原理图可以看出,listview的复用就是:
为了让listview减少在时间和内存上的消耗,Android提供了convertView参数(getView方法的第二个参数,不一定都叫convertView,个人认为叫rowView更好)来实现这一优化。当用户滑动列表时,原先可视的item被滚出屏幕变得不可视,而代表该行的java对象可以被新的可视行复用。也就是说如果列表在手机屏幕中一屏可见的行有7行,当第一行滑出屏幕时,底部新滑出来的第8行可以复用第1行的java对象(即通过item布局inflate出来的view),Android已经把第一行的布局缓存起来,作为可以复用的rowview。

@Override
    public View getView(int i, View convertView, ViewGroup viewGroup) {

        ViewHolder viewHolder = null;

        if(null == convertView){

            LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            convertView = inflater.inflate(R.layout.item_testdisorderitem,null);

        }

        TextView brandChNameTv = (TextView) convertView.findViewById(R.id.item_chName_txt);
        TextView brandEnNameTv= (TextView) convertView.findViewById(R.id.item_enName_txt);

        //set data

        return convertView;
    }
                                                                      代码片段1.3

之前我们说过除了inlating 布局文件和创建java对象对时间和内存的消耗都是昂贵的。使用findViewById()方法也相对地耗时。我们知道每个列表项都会调用getView方法,如果执行<代码片段1.3>那么每显示一个列表项rowView就要调用findViewById来查找各个view。多次findViewById不仅增加了时间消耗,也创建了更多的java对象,从而造成了expensive with regards to time and memory consumption。
为了解决这个问题,引入了View Holder Pattern。
以下对ViewHolder的描述来自于该文章Using lists in Android(ListView) 8.4.节的翻译:
View Holder pattern的使用减少了adapter中对findViewById()的调用。
ViewHoler类是adapter里自定义的一个(静态)内部类,他持有布局文件中相关view的引用。该ViewHolder的引用通过setTag()方法作为一个tag被指派给row view(convertView)。
如果我们接受了一个convertview对象,我们可以通过getTag()方法获取到ViewHolder的实例,然后经由该ViewHolder的引用指定新的属性给Views。
虽然这听起来很复杂,但是使用这种方式比使用findViewById在速度上提高了大约15%。
view holder pattern的目的即为减少findViewById()的调用次数,因为findViewById()这个方法比较耗时,至于两者之间的比较可以自行测试,测试方法可以参考农民伯伯的
因此有了现在的这种模型:

 private class ViewHolder{
        private TextView brandEnNameTv;
        private TextView brandChNameTv;
        private CheckBox followCheckBox;
    }


@Override
public View getView(int i, View viewrow, ViewGroup viewGroup) {

    ViewHolder viewHolder = null;

    if(null == viewrow){

        LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        viewrow = inflater.inflate(R.layout.item_testdisorderitem,null);

        viewHolder = new ViewHolder();
        viewHolder.brandChNameTv = (TextView) viewrow.findViewById(R.id.item_chName_txt);
        viewHolder.brandEnNameTv= (TextView) viewrow.findViewById(R.id.item_enName_txt);

        viewrow.setTag(viewHolder);

    }else {

        viewHolder = (ViewHolder) viewrow.getTag();
    }

    BrandItemInfo brandItemInfo = (BrandItemInfo) getItem(i);
    viewHolder.brandChNameTv.setText(brandItemInfo.getBrandChName());
    viewHolder.brandEnNameTv.setText(brandItemInfo.getBrandEnName());

    return viewrow;
}
                                                                       代码片段1.4

当convertView为空时,创建ViewHolder,通过viewHolder.brandChNameTv = (TextView) convertView.findViewById(R.id.item_chName_txt);来持有布局文件中view的引用。通过setTag(Object)方法把convertView和viewHolder关联起来。当接收到一个converView后,通过getTag(Object)方法获取到viewHolder。这样不仅使用convertView做到了复用现有的views的目的,同时和convertView“绑定的”viewHolder也做到了被复用。
对于ListView、GridView相信大家都不陌生,重写个BaseView,实现对于的几个方法,然后就完成了我们的界面展示,并且在大部分情况下,我们加载特别多的Item也不会发生OOM,大家也都明白内部有缓存机制,都遇到过ItemView复用带来的一些问题,比如异步加载图片,最终造成界面显示的混乱,我们一般会使用setTag,然后回调显示时,避免造成混乱。

设想1:拿ListView为例,如果ListView的ItemView复用机制,所有的ItemView复用同一个,如果在多线程下载图片的情况下,可能最终只有最后一个View显示图片吧,因为你前面的设置setTag(url),后面马上就会将你的Tag的值覆盖掉,最终findViewByTag找到的都是最后一个。由此可见ListView缓存的不是一个,至少是一屏幕可显示的数量。也就是说ListView维护着一个ItemView的池子。

跟大家解释下,为啥缓存了一个屏幕的可显示最大的ItemView数量的池子,我们可能上千个ItemView,仅依靠Tag就能实现不混乱呢。

情景:屏幕每次显示7个Item,ListView一共1000个Item,每个Item上显示一张从网络下载的图片。

getView的代码大概是这样的:

[java] view plaincopy在CODE上查看代码片派生到我的代码片

        @Override  
            public View getView(int position, View convertView, ViewGroup parent)  
            {  
                final String url = getItem(position);  
                View view;  
                if (convertView == null)  
                {  
                    view = LayoutInflater.from(getContext()).inflate(R.layout.photo_layout, null);  
                } else  
                {  
                    view = convertView;  
                }  
                final ImageView photo = (ImageView) view.findViewById(R.id.photo);  
                // 给ImageView设置一个Tag,保证异步加载图片时不会乱序  
                photo.setTag(url);  
                new LoadImgTask(photo).execute(url);  
                return view;  
            }  

下载完成图片,进行photo.getTag().equals(url)来防止图片显示的混乱。
如果我们打开界面,开启了7个线程去下载,此时缓存了这7个ItemView,现在滑动屏幕显示另外下一屏,此时7个ItemView都会复用,会把第一屏设置的Tag全部覆盖掉,没错就是覆盖掉了,又开启7个线程去下载图片,当第一屏的ItemView的图片下载完成后,如果直接findViewByTag然后设置图片会显示在第二屏上,就混乱了,所以一般在显示前都会判断photo.getTag().equals(url);确定了再显示,也就是说第一屏的ItemView图片下载完了,但是Tag被覆盖了,所以即使下载完成了,也不会有任何显示。这就解释了为什么我们防止混乱的代码需要那样去写。

好了,下面从源码角度看一眼ListView内部到底是如何进行缓存的:

跟着ListView,进入父类AbsList,会发现这样一个变量:

/** 
    * The data set used to store unused views that should be reused during the next layout 
    * to avoid creating new ones 
    */  
   final RecycleBin mRecycler = new RecycleBin();  

注释的意思上用一个数据集来存储应当在下一个布局重用的View,避免重新创建新的布局。这个对象应该就是对我们缓存管理的核心类了。继续看这个类,这是一个内部类:

/** 
    * The RecycleBin facilitates reuse of views across layouts. The RecycleBin has two levels of 
    * storage: ActiveViews and ScrapViews. ActiveViews are those views which were onscreen at the 
    * start of a layout. By construction, they are displaying current information. At the end of 
    * layout, all views in ActiveViews are demoted to ScrapViews. ScrapViews are old views that 
    * could potentially be used by the adapter to avoid allocating views unnecessarily. 
    * 
    * @see android.widget.AbsListView#setRecyclerListener(android.widget.AbsListView.RecyclerListener) 
    * @see android.widget.AbsListView.RecyclerListener 
    */  
   class RecycleBin {    private View[] mActiveViews = new View[0];                                                                                                                private ArrayList<View>[] mScrapViews;                                                                                                               <span style="white-space:pre">    </span>  ....                                                                                                                                                 }     

大概意思:这个类是用来帮助在滑动布局时重用View的,RecycleBin包含了两个级别的存储,ActiveViews和ScrapViews,ActiveViews存储的是第一次显示在屏幕上的View;所有的ActiveViews最终都会被移到ScrapViews,ScrapViews存储的是有可能被adapter复用的View。
现在很明确了AbsListView缓存依赖于两个数组,一个数组存储屏幕上当前现实的ItemView,一个显示从屏幕下移除的且可能会被复用的ItemView。下面看ListView里面的代码:

@Override  
    protected void layoutChildren()   
    {  
        if (dataChanged)   
        {  
            for (int i = 0; i < childCount; i++)   
            {  
                recycleBin.addScrapView(getChildAt(i));     
            }  
        } else   
        {  
            recycleBin.fillActiveViews(childCount, firstPosition);  
        }  
        ....  
    }  

[java] view plaincopy在CODE上查看代码片派生到我的代码片
/** 
* Fill ActiveViews with all of the children of the AbsListView. 
* 
* @param childCount The minimum number of views mActiveViews should hold 
* @param firstActivePosition The position of the first view that will be stored in 
*        mActiveViews 
*/  
void fillActiveViews(int childCount, int firstActivePosition)   
{  
    if (mActiveViews.length < childCount)   
    {  
        mActiveViews = new View[childCount];  
    }  
    mFirstActivePosition = firstActivePosition;  

    final View[] activeViews = mActiveViews;  
    for (int i = 0; i < childCount; i++)   
    {  
        View child = getChildAt(i);  
        activeViews[i] = child;   
    }  
}  

可以看出,如果数据发生变化则把当前的ItemView放入ScrapViews中,否则把当前显示的ItemView放入ActiveViews中。那么咱们关键的getView方法到底是在哪调用呢,下面看RecycleBin中的方法:
/*
* Get a view and have it show the data associated with the specified
* position. This is called when we have already discovered that the view is
* not available for reuse in the recycle bin. The only choices left are
* converting an old view or making a new one.
*
* @param position The position to display
* @param isScrap Array of at least 1 boolean, the first entry will become true if
* the returned view was taken from the scrap heap, false if otherwise.
*
* @return A view displaying the data associated with the specified position
*/
View obtainView(int position, boolean[] isScrap)
{
isScrap[0] = false;
View scrapView;
scrapView = mRecycler.getScrapView(position);
View child;
if (scrapView != null)
{

            child = mAdapter.getView(position, scrapView, this);  
            if (child != scrapView)   
            {  
                mRecycler.addScrapView(scrapView);  

            } else   
            {  
                isScrap[0] = true;  
                child.dispatchFinishTemporaryDetach();  
            }  
        } else   
        {  
            child = mAdapter.getView(position, null, this);           
        }  

        return child;  
    }  

可以看到,这个方法就是返回当前一个布局用户当前Item的显示,首先根据position去ScrapView中找,找到后调用我们的getView,此时getView里面的convertView!=null了,然后getView如果返回的View发生变化,缓存下来,否则convertView==null了。

大部分都是引用的别人的博文,在这里仅作整理和记录。感谢博主的分享。

android ListView 实现多选 做android开发久了 ,难免会经常使用ListView ,使用ListView久了 难免会碰到多选的问题,关于多选,做过的应该都了解,会出现选中混乱的问题。以前的解决版本就是使chekedBox不可获取焦点,然后通过点击listview 的item 实现多选,这样倒是勉强解决了,但总觉得很麻烦,另外与我的初衷也是不太符的,我想点的是checkbox,最后却强制让我点成了item,最重要的 如果 阅读详情

相关推荐

Android里ListView里面添加CheckBox实现多选。

1. 我在网上找了很多关于这个方面的文章,因为现在Android里的ListView基本上都用到了ViewHolder,用到了convertView。 2. 网上有的文章也有用到convertView的,只是数据多了CheckBox的选择基本上是出错的了。 3.我想过用Adapter里面用Map 4. 现在我用我的方法来做一个这样的。数据和界面分离开,这才是最好的。 listView的it

琴声悠扬 7002

Android ListView 子项多选并获取多选数据

android Listview 子项多选并获取多选后的内容

MrYanXi的博客 1033

android的listview实现多选删除

android的listview实现多选删除

bxzxcvbnm_123的博客 761

Android 中ListView带复选框多选、全选、不选处理

Android 中ListView带复选框多选、全选、不选处理

dodod2012的专栏 3110

Android listview 实现列表多选

最终实现效果:

gowater123的博客 3393

Android ListView实现多选、全选、反选功能

在实现全选功能之前,首先需要定义一个标志来跟踪全选状态。这通常是一个布尔值变量,用来标识所有列表项是否都被选中。在用户界面上,全选复选框通常会出现在列表顶部,与列表项同步显示选中状态。通过定义一个布尔变量,我们可以控制全选复选框的勾选状态。当列表中的所有项目被选中时,为true,反之则为false。随着用户的选择变化,这个变量的值也会实时更新。反选功能允许用户对列表中的所有项目一次性切换选中状态。

weixin_36369848的博客 562

Android listview多选模式ChoiceMode

9.4 ListView的Choice ModeListView本身带有单选和多选功能,也就是说在单选模式下,它能够记住当前选中的唯一的列表项;在多选模式下,它能够记住目前选取的所有的列表项。这种选择模式共有4种CHOICE_MODE_NONE CHOICE_MODE_SINGLE CHOICE_MODE_MULTIPLE CHOICE_MODE_MULTIPLE_MODAL。使用setChoice

成长的味道 5124

Android ListView多选、长按与删除功能的完整实现

在Android开发中,ListView组件作为常用的列表视图,其多选功能能够提升用户的操作效率。要实现ListView的多选功能,开发者通常需要借助于接口。这个接口允许我们监听和响应长按、点击等用户交互,从而实现多选的效果。

weixin_36213081的博客 774

android中多选ListView的实现

android中多选ListView的实现一、实现效果 开始效果 多选后点击按钮效果 二、实现过程 layout布局中添加ListView,将 android:choiceMode="multipleChoice"属性设置成这样 自定义ListView的item布局,这个布局和非多选的ListView的item布局设置一样。效果如下: 为ListView的item布局写一个自定义View。正常的Li

jiyiren的博客 1198

实现Android ListView中Checkbox的多选功能

在Android开发中,ListView是展示滚动列表数据的常用组件。当我们需要在ListView中实现复杂的列表项时,自定义适配器便显得尤为关键。适配器(Adapter)在ListView和数据源之间扮演着桥梁的角色,它负责将数据源中的数据映射到ListView中展示的列表项上。要实现一个带有Checkbox的ListView列表项,第一步是设计一个XML布局文件,这个文件将定义每个列表项的视觉结构。在XML文件中,我们通常需要一个LinearLayout作为根布局,以便于水平或垂直排列内部控件。

weixin_35750483的博客 381

2026深度破解:OpenClaw开源AI框架架构与实战全景解析

2026年初,一款名为OpenClaw的开源AI Agent框架以惊人的速度席卷全球开发者社区,短短数周GitHub星标突破20万,成为史上增长最快的开源项目。本文从架构设计、核心原理、代码实现和工程实战四个维度,深度剖析OpenClaw的技术内核,帮助开发者从理解到实践,快速掌握这一革命性的AI开发框架。

fox0329的博客 2373

android的listview多选功能,Android ListView实现单选及多选等功能示例

本文实例讲述了Android ListView实现单选及多选等功能的方法。分享给大家供大家参考,具体如下:在项目中也遇到过给ListView的item添加选择功能。比如一个网购APP,有个历史浏览页面,这个页面现点击item单选/多选及全选删除功能。当时也是通过在数据中添加一个是否选择的字段来记录item的状态,然后根据这个字段有相应的position位置进行选择状态更改及删除操作。刚刚看了And...

weixin_31639069的博客 1375

手把手拆解:储能电站如何实现‘孤岛运行’与‘黑启动’?从SVPWM控制到无缝并网

本文深入解析储能电站的孤岛运行与黑启动技术,从SVPWM控制策略到电网重构实战。通过详细的三环控制架构和黑启动五阶段技术路线,展示储能电站在电网故障时如何快速切换为独立电压源并实现电网重建。文章还探讨了虚拟惯量补偿、多站协同控制等前沿技术,为电力系统应急恢复提供关键解决方案。

weixin_30509393的博客 304

Android Listview实现多选

布局文件 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height=...

ren648154292的博客 633

给MATLAB安装runtime插件

输入你刚刚下载压缩包的位置(小白提示:在 此电脑 中找到压缩包位置,右键属性复制位置)(!设置好以后然后填写下面输出exe文件的信息,包括文件的名字、作者、Email、公司、概述、描述,下面还可以选择额外的安装选项,exe文件运行需要的其他文件(图像、子程序等)、提供给用户的文件(readme.txt等)(很多方法是官网下载,但在官网下载还是会版本不对应,所以直接在你所用的MATLAB里搜索安装链接最靠谱)(!5.可以打包程序了(你发送文件的人电脑里没有MATLAB也可以查看运行你的程序了)

Pei_hua100的专栏 1万+

学习stm32H7之路开始(STM32H7系列1) 前期准备,HAL库框架

2020.01.07 几个重要的参考网址 1.电子工程世界网 http://tags.eeworld.com.cn/tags/STM32H7 链接: link. 2.转:https://blog.youkuaiyun.com/simon223/article/list/2?t=1 链接: link. ———————————————— 版权声明:本文为优快云博主「Simon223」的原创文章,遵循 CC 4....

kengkengkeng963的博客 3408

Android实现LIstView条目单选和多选RadioButton

看效果图是不是你想要的 ListView的布局 <ListView android:choiceMode="singleChoice" android:background="#fff" android:layout_marginTop="5dp" android:id="@+id/listview_template" and

sungeAndroid的博客 1402

从TM1到TM9:手把手教你用Wireshark抓包分析LTE下行调度与传输模式切换

本文详细解析了如何使用Wireshark抓包分析LTE下行调度中的传输模式切换,从TM1到TM9的动态调整过程。通过实战案例,包括小区边缘移动、高速场景和多用户调度,揭示eNodeB如何基于信道质量指标(如RSRP、SINR)动态切换传输模式,并提供关键信令解析和优化建议,助力网络工程师提升LTE网络性能。

weixin_42651748的博客 315

Android 带checkbox的listView 实现多选,全选,反选,删除

activity_main.xml "http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent"

从零开始 2752

工业视觉光源频闪控制的三种核心模式与选型实战

本文深入解析工业视觉系统中光源频闪控制的三种核心模式:光源主控、相机主控与硬同步。针对高速飞拍、缺陷检测等场景,详细对比了各模式的时序原理、硬件要求与适用场景,并提供了基于产线速度与检测需求的实战选型指南,帮助工程师有效消除运动模糊、提升成像质量与系统稳定性。

weixin_29299807的博客 433

0.1 专栏导读:为什么需要从 MM 理解 HMM

本文探讨了GPU计算框架中CPU与GPU内存管理的困境,介绍了Linux内核的HMM(Heterogeneous Memory Management)解决方案。传统显式拷贝模型存在编程复杂、指针失效等问题,而HMM通过共享虚拟地址空间、自动页面迁移等机制实现透明内存管理。文章分析了HMM依赖的Linux内存管理基础设施,包括页表遍历、MMU通知、ZONE_DEVICE等核心组件,并梳理了从经典MM到支持异构设备的进化历程。最后给出了学习HMM的8层知识体系,强调理解底层MM机制是掌握HMM的关键。

图形/计算GPU的驱动与虚拟化技术分享园地 762

android中ListView的setItemChecked方法 实现多选

1.要在XML中为listView设置choiceMode  为singleChoice或者mutipleChoice 也可以在代码中设置 listView.setChoiceMode(int mode); 2.listView的item一定要是checkable的。否则不会生效。这一点也是从网上看的资料,具体没有研究了。 最常见还是集成baseAdapter 使用的

普羅●米修斯 ——— HelloWorld 1万+

基于STM32L4XX 、HAL库的TMC2226-SA-T步进电机驱动器驱动程序应用设计

集成的功率MOSFET可处理高达2A RMS的电机电流,并具备保护与诊断功能,确保运行稳健可靠。作为业界最先进的STEP/DIR步进电机驱动系列,该芯片通过升级设计实现无噪音、高精度运行,为用户提供高性价比且极具竞争力的解决方案。// 用于PDN_UART单线通信。// HAL_UART_Transmit - 注意PDN_UART是单线,收发共线。.huart = &huart1, // PDN_UART连接的USART。均方根步进/方向控制接口,提供8、16、32或64微步针设置,

PP_Cottage的博客 623

Android实现listview列表多选 (附带源码)

Android实现listview列表多选 (附带源码)

欢迎来到我的博客!这里是一个专注于计算机技术的分享平台,涵盖编程开发、算法研究、系统架构、软件工程等多个领域。无论你是初学者还是资深开发者,都能在这里找到有价值的内容。 1491

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

android 列表滑动多选,Android实现ListView嵌套Checkbox真正的多选、全选、反选

我们在开发APP的时候,很多情况下会使用到ListView嵌套CheckBox的情况,其实很多人要说这个其实很简单了,并没有那么复杂,为什么还要单独用一篇博客来写呢?事实上并非如此,我们在使用ListView嵌套CheckBox复选框的时候会出现很多问题,废话不多说,直接进入主题,首先我们来看ListView的item的布局文件:listview_item.xmlandroid:layout_wi...

weixin_42134240的博客 1263

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

Android——ListView使用ActionMode实现的上下文长按多选菜单

操作环境:Android Studio 以及自带的模拟器,相关配置如下 话不多说,先上结果截图。 第一张是初始应用的菜单界面。第二张是长按选中之后的操作界面。由图中可以看出,长按之后,选中项会标绿(ps:原谅我这渣渣的审美),并且上面标题菜单栏会显示选中了几项,出现三个选项,分别是返回,选中和删除。这个菜单是可以定制的,我这边三个选项都设置成了返回,毕竟只是为了实现这个长按多选菜单(请允许我...

小白 1260

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

上一篇: 如何“任性”使用Android的drawText()
下一篇: Android知识点学习笔记——Service服务
ProbuINg
博客等级 码龄14年 10粉丝 77原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值