欢迎来真孝善网,为您提供真孝善正能量书籍故事!

深入解析Android开发:ListView与AdapterView核心技术详解

时间:11-08 现代故事 提交错误

当需要显示数据时,ListView会从Adapter中取出数据来加载显示,如下图所示。

ListView负责以列表的形式显示Adapter提供的内容。

3.2 缓存原理

想象一个场景:如果将所有的数据采集信息都加载到ListView中进行显示,如果ListView要为每个数据创建一个视图,会占用很大的空间。记忆

为了节省空间和时间,ListView并没有为每个数据创建一个视图,而是使用Recycler组件来回收和复用View。

当屏幕需要显示x个Item时,那么ListView就会创建x+1个视图;当第一个Item离开屏幕时,该Item的View会被回收到缓存中,进入屏幕的Item的View会先从缓存中获取。

笔记:

该物品只有在完全离开屏幕后才能重新使用。这就是为什么ListView需要比屏幕需要显示的多创建一个视图:缓冲的显示视图是:第一个Item离开屏幕有一个过程,会出现1第1个Item的下半部分 第8个Item上半部分同时在屏幕中显示的状态,缓存的View此时仍然无法使用,只能用新创建的View实例继续演示。

假设:屏幕只能显示5个Item,那么ListView只会创建(5+1)个Item的视图;当第一个Item完全离开屏幕时,会被回收到缓存中重新使用(用于显示第7个Item)示意图

4. 具体使用

1. 生成方式生成列表视图(ListView)主要有两种方式:

直接用ListView创建,让Activity继承ListActivity2. xml文件配置信息AbsListView的常用属性及相关方法:

属性说明备注android:choiceMode 列表选择行为,默认:none 无选择行为选择方式:none:不显示任何选中项singleChoice:允许单选multipleChoice:允许多选multipleChoiceModal:允许多选(将适配器的第二个参数放在Activity 更改为支持选择的布局) android:drawSelectorOnTop 如果该属性设置为true,则选中的列表项将显示在android:listSelector 集的顶部所单击项目的图片。如果该属性设置为true,则选中的列表项将显示在顶部android:fastScrollEnabled 设置是否允许快速滚动。如果该属性设置为true,则将显示滚动图标,并且允许用户拖动滚动图标进行快速滚动。 android:listSelector 指定在选中的列表项上绘制的Drawable android:scrollingCache 滚动时是否使用缓存。如果设置为true,滚动时会使用缓存android:stackFromBottom 设置是否从底部开始排列列表项android:transcriptMode 指定列表添加新选项时是否自动滑动到底部显示新选项。禁用:取消transcriptMode模式;默认正常:当收到数据集更改通知时自动滑到底部,并且仅当屏幕上显示最后一个选项时。 alwaysScroll:无论列表中当前显示什么选项,列表都会自动滑动到底部以显示最新的选项。 Listview提供的XML属性:

XML属性说明备注android:divider 设置List列表项的分隔条(可以用颜色分隔,也可以用图片(Drawable)分隔)。不要设置列表之间的分界线。可以通过设置属性为@nullandroid:dividerHeight来设置分隔栏的高度android:background 属性设置list 背景android:entries 指定一个数组资源,Android会根据该数组资源生成ListView。 android:footerDividerEnabled。如果设置为false,则不会在页脚视图andorid:headerDividerEnabled 之前绘制分隔线。如果设置为false,则分隔线不会在标题View 之前绘制。第

5. Adapter简介

条适配器本身就是一个接口。 Adapter接口及其子类的继承关系如下:

Adapter接口及其子类的继承关系。 pngAdapter接口派生了两个子接口ListAdapter和SpinnerAdapter。 ListAdapter为AbsAdapter提供列表项,SpinnerAdapter为AbsSpinner提供列表项。

ArrayAdapter、SimpleAdapter、SimpleCursorAdapter 和BaseAdapter 都是实现适配器的常用类。 ArrayAdapter:一个简单易用的Adapter,用于绑定数组作为列表项的数据源,支持泛型操作。 SimpleAdapter:功能强大的Adapter,用于绑定XML中的控件作为列表项的数据源SimpleCursorAdapter:与SimpleAdapter类似,用于绑定一个游标(直接从数据中取出数据)作为列表项的数据源BaseAdapter:可定制的ListView,通用用于扩展。扩展BaseAdapter 允许最大程度地自定义每个列表项。

6. 常用适配器介绍

6.1 ArrayAdapter

定义简单易用的Adapter,用于绑定数组作为列表项的数据源,支持泛型操作

步骤1. 在xml文件布局上实现ListView?xml version="1.0"encoding="utf-8"?Rendering.png2. 在MainActivity上定义一个链表,将所要展示的数据以存放在里面3. 构造ArrayAdapter对象,设置适配器4. 将LsitView绑定到ArrayAdapter上如下图:

公共类MainActivity 扩展AppCompatActivity {

@覆盖

protected void onCreate(Bundle savingInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

ListView listView=(ListView) findViewById(R.id.list_item);

//定义一个链表,存放要显示的数据

最终ListadapterData=new ArrayList();

//存储要显示的数据

for (int i=0; i 20; i++) {

adapterData.add("ListItem" + i);

}

//创建ArrayAdapter对象适配器并设置适配器

ArrayAdapter适配器=新的ArrayAdapter(这个,

android.R.layout.simple_list_item_1,adapterData);

//将LsitView绑定到ArrayAdapter

listView.setAdapter(适配器);

}

}创建ArrayAdapter对象需要指定三个参数:

context:表示方向Android应用程序的界面textViewRseourceld:资源ID,表示TextView数组:列表项显示的数据5. 在xml文件布局添加资源文件TextView,该TextView组件将作列表项的组件?xml version="1.0"encoding="utf-8"?android:textSize="24sp"

最终效果图

最后Rendering.png缺点ArrayAdapter比较简单易用,但是每个列表项只能是一个TextView,在功能实现上有很大的限制。

6.2 SimpleAdapter

定义:功能强大的Adapter,用于绑定XML中的控件作为列表项的数据源特点:每个列表项都可以自定义(自定义布局),可以满足大多数开发需求场景,灵活性更大步骤1. 在xml文件布局上实现ListView?xml版本="1.0"编码="utf-8"?2. 根据实际需求定制列表项:实现ListView每行的xml布局(即item布局)?xml版本="1.0"编码="utf-8"?3. 定义一个HashMap构成的列表以键值对的方式存放数据010 -590004. 构造SimpleAdapter对象,设置适配器公共类MainActivity 扩展AppCompatActivity {

//定义数组来填充数据

私有字符串[]名称=新字符串[]{

"威龙注塑机"、"巴龙注塑机"、"恐龙注塑机"};

私有字符串[]地址=新字符串[]{

"广东","北京","黑龙江"};

私人int[] lowerest_wholesale=新int[]{

11,22,33};

私有int[] 价格=new int[]{

11,22,33};

私有int[] 图片=new int[]{

R.drawable.home_selected,

R.drawable.home_selected,

R.drawable.home_selected };

@覆盖

protected void onCreate(Bundle savingInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

//定义一个由HashMap组成的列表,以键值对的形式存储数据

ArrayList列表项=new ArrayList();

//循环填充数据

for(int i=0;imap=new HashMap();

map.put("名称", 名称[i]);

map.put("地址", 地址[i]);

map.put("lowerest_wholesale", lowerest_wholesale[i]);

map.put("价格", 价格[i]);

map.put("图片", 图片[i]);

listItem.add(地图);

}

//构造一个SimpleAdapter对象并设置适配器

SimpleAdapter mSimpleAdapter=new SimpleAdapter(这个,

listItem, //需要绑定的数据

R.layout.item_imformation,//每行的布局

new String[] {"名称","地址","lowerest_wholesale","价格","图片"},

//数组中数据源的key对应定义布局的View

new int[] {R.id.name,R.id.address,R.id.lowerest_wholesale,R.id.price,R.id.picture});

ListView列表=(ListView) findViewById(R.id.list_item);

//为ListView绑定适配器

list.setAdapter(mSimpleAdapter);

}

}

结果显示

结果显示

6.3 BaseAdapter

5. 将LsitView绑定到SimpleAdapter上可定制的ListView,一般用于扩展。扩展BaseAdapter 允许最大程度地自定义每个列表项

定义定义主要xml 布局。根据需要定义ListView每一行实现的xml布局。定义一个Adapter类继承BaseAdapter并重写里面的方法。定义一个由HashMap组成的列表,以键值对的形式存储数据。构造Adapter对象并设置适配器。将LsitView 绑定到适配器。使用步骤:要使用BaseAdapter,必须编写一个类来继承它。同时BaseAdapter是一个抽象类,如果继承它,就必须实现它的方法。

类MyAdapter 扩展BaseAdapter {

private LayoutInflater mInflater;//获取一个LayoutInfalter对象,用于导入布局

//构造函数

公共MyAdapter(上下文上下文,ArrayListlistItem){

this.mInflater=LayoutInflater.from(context);

this.listItem=listItem;

}//声明构造函数

@覆盖

公共int getCount() {

返回listItem.size();

}//该方法返回适配器中表示的数据集合中的条目数

@覆盖

公共对象getItem(int 位置) {

返回listItem.get(位置);

}//该方法返回数据集合中指定索引位置对应的数据项

@覆盖

公共长getItemId(int 位置) {

返回位置;

}//该方法返回列表中指定索引对应的行id

@覆盖

公共视图getView(int 位置,视图ConvertView,ViewGroup 父级){

返回空值;

}//该方法返回指定索引对应的数据项的视图,该视图尚未完成。

}先定义一个Adapter类继承BaseAdapter,并重写里面的方法BaseAdapter的灵活性在于它要重写很多方法,其中最重要的是getView()方法。我们结合以上四种改写方法来理解这里主要讲一下BaseAdapter里必须要重写的4个方法图。其中,我们重点关注重写的getView()方法。总共有三种类型。

/**

* 重写方法1:直接返回指定索引对应的数据项的视图

*/

@覆盖

公共视图getView(int 位置,视图ConvertView,ViewGroup 父级){

查看项目=mInflater.inflate(R.layout.item,null);

ImageView img=(ImageView)item.findViewById(R.id.ItemImage);

TextView 标题=(TextView)item.findViewById(R.id.ItemTitle);

TextView 测试=(TextView)item.findViewById(R.id.ItemText);

按钮btn=(Button) item.findViewById(R.id.ItemBottom);

img.setImageResource((Integer) listItem.get(position).get("ItemImage"));

title.setText((String) listItem.get(position).get("ItemTitle"));

test.setText((String) listItem.get(position).get("ItemText"));

退货;

}

//缺点:

//每次调用getView()时,都要通过findViewById()再次找到View组件,并重新绘制View。

//当列表项数据量较大时,会严重影响性能,体现在下拉慢、卡住。

/**

* 重写方法2:使用convertView作为View缓存(优化)

* 具体原则:

* //a.使用convertView作为getView()的输入参数和返回参数形成反馈

* //b.形成了Adapter的itemView复用机制,减少了View重绘的次数。

*/

@覆盖

公共视图getView(int 位置,视图ConvertView,ViewGroup 父级){

//检查是否有可复用的View,如果没有则重绘

if(convertView==null)

{

ConvertView=mInflater.inflate(R.layout.item, null);

}

ImageView img=(ImageView)convertView.findViewById(R.id.ItemImage);

TextView标题=(TextView)convertView.findViewById(R.id.ItemTitle);

TextView测试=(TextView)convertView.findViewById(R.id.ItemText);

按钮btn=(Button) ConvertView.findViewById(R.id.ItemBottom);

img.setImageResource((Integer) listItem.get(position).get("ItemImage"));

title.setText((String) listItem.get(position).get("ItemTitle"));

test.setText((String) listItem.get(position).get("ItemText"));

返回转换视图;

//最后返回convertView形成反馈

}

//优点:减少View重绘次数

//缺点:但是每次都要通过findViewById()找到View组件

/**

* 重写方法3:在方法2的基础上,使用ViewHolder实现更具体的缓存:View组件缓存

* 具体原则:

* //a.使用convertView作为getView()的输入参数和返回参数形成反馈

* //b.形成了Adapter的itemView复用机制,减少了View重绘的次数。

*/

静态类ViewHolder

{

公共ImageView img;

公共TextView 标题;

公共TextView 文本;

公共按钮btn;

}

@覆盖

公共视图getView(int 位置,视图ConvertView,ViewGroup 父级){

ViewHolder 持有者;

if(convertView==null)

{

持有者=新的ViewHolder();

ConvertView=mInflater.inflate(R.layout.item, null);

holder.img=(ImageView)convertView.findViewById(R.id.ItemImage);

holder.title=(TextView)convertView.findViewById(R.id.ItemTitle);

holder.text=(TextView)convertView.findViewById(R.id.ItemText);

holder.btn=(Button)convertView.findViewById(R.id.ItemBottom);

convertView.setTag(holder); } else { holder = (ViewHolder)convertView.getTag(); } holder.img.setImageResource((Integer) listItem.get(position).get("ItemImage")); holder.title.setText((String) listItem.get(position).get("ItemTitle")); holder.text.setText((String) listItem.get(position).get("ItemText")); return convertView; } // 优点:重用View时就不用通过 findViewById()重新 寻找View组件,同时也减少了重绘View的次数,是ListView使用的最优化方案方案3(通过convertView+ViewHolder重写getView())是ListView使用的最优化,所以非常推荐大家使用 总结:ListView的优化 示意图最优化方案的完整实现方案定义主xml的布局 activity_main.xml:根据需要,定义ListView每行所实现的xml布局(item布局) item.xml:定义一个Adapter类继承BaseAdapter,重写里面的方法。(利用convertView+ViewHolder来重写getView()) MyAdapter.java package scut.learnlistview; import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.Button; import android.widget.ImageView; import android.widget.TextView; import java.util.ArrayList; import java.util.HashMap; class MyAdapter extends BaseAdapter { private LayoutInflater mInflater;//得到一个LayoutInfalter对象用来导入布局 ArrayList>listItem; public MyAdapter(Context context,ArrayList>listItem) { this.mInflater = LayoutInflater.from(context); this.listItem = listItem; }//声明构造函数 @Override public int getCount() { return listItem.size(); }//这个方法返回了在适配器中所代表的数据集合的条目数 @Override public Object getItem(int position) { return listItem.get(position); }//这个方法返回了数据集合中与指定索引position对应的数据项 @Override public long getItemId(int position) { return position; }//这个方法返回了在列表中与指定索引对应的行id //利用convertView+ViewHolder来重写getView() static class ViewHolder { public ImageView img; public TextView title; public TextView text; public Button btn; }//声明一个外部静态类 @Override public View getView(final int position, View convertView, final ViewGroup parent) { ViewHolder holder ; if(convertView == null) { holder = new ViewHolder(); convertView = mInflater.inflate(R.layout.item, null); holder.img = (ImageView)convertView.findViewById(R.id.ItemImage); holder.title = (TextView)convertView.findViewById(R.id.ItemTitle); holder.text = (TextView)convertView.findViewById(R.id.ItemText); holder.btn = (Button) convertView.findViewById(R.id.ItemBottom); convertView.setTag(holder); } else { holder = (ViewHolder)convertView.getTag(); } holder.img.setImageResource((Integer) listItem.get(position).get("ItemImage")); holder.title.setText((String) listItem.get(position).get("ItemTitle")); holder.text.setText((String) listItem.get(position).get("ItemText")); holder.btn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { System.out.println("你点击了选项"+position);//bottom会覆盖item的焦点,所以要在xml里面配置android:focusable="false" } }); return convertView; }//这个方法返回了指定索引对应的数据项的视图 }4.在MainActivity里: 定义一个HashMap构成的列表,将数据以键值对的方式存放在里面。构造Adapter对象,设置适配器。将LsitView绑定到Adapter上。MainActivity.java package scut.learnlistview; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.ListView; import android.widget.SimpleAdapter; import java.util.ArrayList; import java.util.HashMap; import java.util.List; public class MainActivity extends AppCompatActivity { private ListView lv; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); lv = (ListView) findViewById(R.id.listView1); /*定义一个以HashMap为内容的动态数组*/ ArrayList>listItem = new ArrayList>();/*在数组中存放数据*/ for (int i = 0; i< 100; i++) { HashMapmap = new HashMap(); map.put("ItemImage", R.mipmap.ic_launcher);//加入图片 map.put("ItemTitle", "第" + i + "行"); map.put("ItemText", "这是第" + i + "行"); listItem.add(map); } MyAdapter adapter = new MyAdapter(this, listItem); lv.setAdapter(adapter);//为ListView绑定适配器 lv.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterViewarg0, View arg1, int arg2, long arg3) { System.out.println("你点击了第" + arg2 + "行");//设置系统输出点击的行 } }); } }

运行结果

点击输出结果:

注:进阶使用 = 添加头部 & 尾部View

在日常使用中,我们常常会需要在ListView头部 / 尾部添加视图

步骤1:添加头部 / 尾部视图

header_view.xml

步骤2:添加到ListView中

private ListView lv; View view = LayoutInflater.from(MainActivity.this).inflate(R.layout.header_view, null); lv.addHeaderView(view); // lv.addFooterView(view); // 添加到底部View

示意图

7. 与RecylerView的区别

image.png

8. 总结

本文全面介绍了ListView与AdapterView下面我将继续对Android中的知识进行深入讲解 ,感兴趣的同学可以继续关注Carson_Ho的简书相关系列文章阅读Carson带你学Android:学习方法 Carson带你学Android:四大组件 Carson带你学Android:自定义View Carson带你学Android:异步-多线程 Carson带你学Android:性能优化 Carson带你学Android:动画

用户评论

三年约

想学习Android开发?这个教程看起来很不错啊!

    有10位网友表示赞同!

信仰

好久没碰过ListView和AdapterView了,现在需要用到,正好看看这篇文章。

    有14位网友表示赞同!

等量代换

Carson老师的讲解总是清清楚楚易懂,期待能学到不少实用的知识。

    有11位网友表示赞同!

你tm的滚

这篇教程终于来了!我一直想学习Android界面相关的细节。

    有14位网友表示赞同!

浮世繁华

ListView和AdapterView都是Android开发必备的内容,要好好收藏这篇教程。

    有19位网友表示赞同!

我怕疼别碰我伤口

对Android新手来说这个教程简直是 manna from heaven!

    有16位网友表示赞同!

淡抹丶悲伤

希望这篇文章不仅讲解理论知识,还会提供一些实战案例。

    有8位网友表示赞同!

無極卍盜

准备开始学习Android开发了, 这篇文章正好能帮我入门!

    有17位网友表示赞同!

安之若素

看了一下文章目录,内容涵盖的挺全面,很有帮助。

    有14位网友表示赞同!

颓废i

这个周末要好好学习一下ListView和AdapterView的使用方法。

    有17位网友表示赞同!

一生只盼一人

Carson老师的视频教程我也看过,这篇文章肯定很详细!

    有20位网友表示赞同!

坏小子不坏

Android界面设计真的很重要,这篇教程能让我更好地理解这些技巧。

    有13位网友表示赞同!

追忆思域。

终于可以解决我之前开发过程中遇到的ListView问题了!

    有10位网友表示赞同!

厌归人

收藏起来以后再学习的时候看看,应该会很有帮助。

    有10位网友表示赞同!

旧事酒浓

对于想要深入学习Android开发的朋友来说,这篇文章必不可少。

    有19位网友表示赞同!

夏日倾情

不知道这篇教程是否包含不同版本Android的差异分析?

    有10位网友表示赞同!

凝残月

希望这篇文章能让我理解ListView和AdapterView背后的原理。

    有13位网友表示赞同!

黑夜漫长

我已经对Android开发产生了浓厚的兴趣,这篇文章正好可以帮我更进一步!

    有16位网友表示赞同!

【深入解析Android开发:ListView与AdapterView核心技术详解】相关文章:

1.蛤蟆讨媳妇【哈尼族民间故事】

2.米颠拜石

3.王羲之临池学书

4.清代敢于创新的“浓墨宰相”——刘墉

5.“巧取豪夺”的由来--米芾逸事

6.荒唐洁癖 惜砚如身(米芾逸事)

7.拜石为兄--米芾逸事

8.郑板桥轶事十则

9.王献之被公主抢亲后的悲惨人生

10.史上真实张三丰:在棺材中竟神奇复活