Android Studio 通过 ListView 学习 ArrayAdapte
ListView
•前言
ListView 绝对可以称得上是 Android 中最常用的控件之一,几乎所有的应用程序都会用到它。
由于手机屏幕空间有限,能够一次性在屏幕上显示的内容并不多,当我们的程序中有大量的数据需要展示的时候,就可以借助 ListView 来实现。
ListView 允许用户通过手指上下滑动的方式将屏幕外的数据滚动到屏幕内,同时屏幕上原有的数据则会滚动出屏幕。
其实你每天都在使用这个控件,比如查看 QQ聊天记录,翻阅微博消息,等等。
•ListView简介
ListView 的直接父类是 View.Group,也就是说,他自己定义了子排列 View 的规则。
ListView 和所要展示的内容(数据源)之间需要 Adapter(适配器) 来实现。
Adapter 是一个桥梁,对 ListView 的数据进行管理。
数据来源不同,所使用的 Adapter 也不同,数据源(Data source)、Adapter和列表(ListView)之间的关系如下图所示:
•ListView相关属性
- android:dividerHeight="2dp" : 设置分割线高度
- android:divider="@color/red" : 设置分割条,可以用颜色分割,也可以用 drawable 资源分割
- android:entries="@array/myarray" : 设置 ListView 显示的内容
•ListView的简单用法
在 res/values 下创建一个 arrays.xml 文件,添加代码如下:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string-array name="myarray">
<item>关羽</item>
<item>孙尚香</item>
<item>娜可露露</item>
</string-array>
</resources>新建一个 Activity,添加代码如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="10dp"> <TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Test Array Adapter"
android:textSize="20sp"
/> <!-- 为 ListView 设置红色的分割线
并将分割线宽度设置为 2dp -->
<ListView
android:id="@+id/lv_array_adapter"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:divider="@color/red"
android:dividerHeight="2dp"
android:entries="@array/myarray"
/> </LinearLayout>
•运行效果
•Adapter简介
Adapter 的继承关系如下图所示:
Adapter 是一个接口,ListAdapter 继承了 Adapter,也是一个接口,并需要子类实现。
BaseAdapter 实现了 ListAdapter,他是一个抽象类。
SimpleAdapter 继承自 BaseAdapter,他是 Adapter 的一个实例对象。
另外,还有 ArrayAdapter 和 SimpleCursorAdapter 也是 Adapter 的实例对象。
- ArrayAdapter:支持泛型操作,最简单的一个Adapter,只能展现一行文字
- SimpleAdapter:同样具有良好扩展性的一个Adapter,可以自定义多种效果
- BaseAdapter:抽象类,实际开发中我们会继承这个类并且重写相关方法,用得最多的一个Adapter
- SimpleCursorAdapter:用于显示简单文本类型的listView,一般在数据库那里会用到,不过有点过时, 不推荐使用
ArrayAdapter
•示例一
在 res/layout 新建 activity_array_adapter.xml 文件,添加代码如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="10dp"> <TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Test Array Adapter"
android:textSize="20sp"
/> <!-- 为 ListView 设置红色的分割线
并将分割线宽度设置为 2dp -->
<ListView
android:id="@+id/lv_array_adapter"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:divider="@color/red"
android:dividerHeight="2dp"
/> </LinearLayout>新建 ArrayAdapterActivity.java 文件,添加代码如下:
public class ArrayAdapterActivity extends AppCompatActivity { private ListView listview; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_array_adapter); String[] s = new String[]{"关羽", "孙尚香", "娜可露露"};
ArrayAdapter<String> adapter = new ArrayAdapter<>(this, R.layout.array_adapter_item, s); listview = findViewById(R.id.lv_array_adapter);
listview.setAdapter(adapter);
} }在这段代码中,定义了一个字符串数组 s ,不过数组 s 中的数据是无法直接传递给 ListView 的;
我们还需要借助适配器来完成(这里我们借助 ArrayAdapter 这个适配器);
ArrayAdapter 可以通过泛型来指定要适配的数据类型,然后再构造函数中把要适配的数据传入;
ArrayAdapter 有多个构造函数的重载,我们应该根据实际情况选择最合适的一种;
这里由于我们提供的数据都是字符串,因此将 ArrayAdapter 的泛型指定为 String;
然后在 ArrayAdapter 的构造函数中依次传入:
- 当前上下文(this)
- ListView子项布局的 id(R.layout.array_adapter_item)
- 适配的数据(s)
R.layout.array_adapter_item 布局代码如下:
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/textView"
android:textSize="20sp"
android:textColor="@color/black"> </TextView>此布局用来设置显示的字体(关羽、孙尚香、娜可露露)风格。
•运行效果
•示例二
只能显示一段文本的 ListView 实在是太单调了,我们现在就来对 ListView 的界面进行定制,让它可以显示更加丰富的内容。
首先需要准备一组图片,分别对应上面提供的英雄:
![]()
![]()
$guan\_yu.jpg$ $sun\_shang\_xiang.jpg$ $na\_ke\_lu\_lu.jpg$
接着定义一个实体类,作为 ListView 适配器的适配类型。
新建类 Person,代码如下:
public class Person {
private String name;//英雄名称
private int imgId;//对应图片id public Person(String name,int imgId){
this.name = name;
this.imgId = imgId;
} public String getName() {
return name;
} public int getImgId() {
return imgId;
}
}Person 类中只有两个字段,name 表示英雄名称,imgId 表示英雄对应图片的资源 id。
然后需要为 ListView 的子项指定一个我们自定义的布局;
在 layout 目录下新建 person_item,添加代码如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:padding="10dp"
android:layout_marginTop="20dp"> <ImageView
android:id="@+id/person_img"
android:layout_width="100dp"
android:layout_height="150dp"
android:scaleType="centerCrop"/> <TextView
android:id="@+id/person_name"
android:layout_width="match_parent"
android:layout_height="150dp"
android:layout_marginLeft="10dp"
android:gravity="center"
android:textSize="20sp"
android:textColor="@color/red"
/> </LinearLayout>在这个布局中,我们定义了一个 ImageView 用来显示图片,有定义了一个 TextView 用来显示名称。
接下来需要创建一个自定义的适配器,这个适配器继承自 ArrayAdapter,并将泛型指定为 Person 类。
新建 PersonAdapter 类,添加代码如下:
public class PersonAdapter extends ArrayAdapter<Person> { private Context context;
private int resource; public PersonAdapter(@NonNull Context context, int resource, @NonNull List<Person> objects) {
super(context, resource, objects);
this.context = context;
this.resource = resource;
} @NonNull
@Override
public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
Person person = getItem(position);//获取当前项的 Person 实例 View view = LayoutInflater.from(context).inflate(resource, parent, false);
ImageView img = view.findViewById(R.id.person_img);
TextView name = view.findViewById(R.id.person_name); img.setImageResource(person.getImgId());
name.setText(person.getName()); return view;
}
}PersonAdapter 重写了父类的一组构造函数,用于将上下文、ListView 子项布局 id 和数据都传递进来。
另外又重写了 getView() 方法,这个方法在每个子项被滚动到屏幕内的时候被调用。
在 getView() 方法中,首先通过 getItem() 方法得到当前项的 Person 实例,然后使用 LayoutInflater 来为这个子项加载我们传入的布局。
通过 LayoutInflater 的 from() 方法可以构建出一个 LayoutInflater 对象,然后调用 inflate() 方法动态加载一个布局文件。
inflate() 方法接收三个参数:
- 第一个参数是要加载的布局文件的 id(resource)
- 第二个参数是给加载好的布局再添加一个父布局(parent)
- 第三个参数指定成 false
接下来调用 view 的 findViewByid() 方法分别获取到 ImageView 和 TextView 的实例。
并分别调用他们的 setImageResource() 和 setText() 方法来设置现实的图片和文字。
最后将布局返回,这样我们的适配器就完成了。
最后修改 ArrayAdapterActivity.java 中的代码,如下所示:
public class ArrayAdapterActivity extends AppCompatActivity { private ListView listview; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_array_adapter); PersonAdapter adapter = new PersonAdapter(ArrayAdapterActivity.this, R.layout.person_item, getData()); listview = findViewById(R.id.lv_array_adapter);
listview.setAdapter(adapter);
} private List<Person> getData() {
List<Person> list = new ArrayList<>(); Person guanYu = new Person("关羽", R.drawable.guan_yu);
list.add(guanYu); Person sunShangXiang = new Person("孙尚香", R.drawable.sun_shang_xiang);
list.add(sunShangXiang); Person naKeLL = new Person("娜可露露", R.drawable.na_ke_lu_lu);
list.add(naKeLL); return list;
}
}可以看到,这里添加了一个 getData() 方法,用于获取数据。
接着在 onCreate() 方法中创建了 PersonAdapter 对象,并将 PersonAdapter 作为适配器传递个 ListView。
这样定值 ListView 界面的任务就完成了。
•运行效果
•提升ListView 的运行效率
之所以说 ListView 这个控件很难用,是因为它有很多细节可以优化,其中运行效率就是很重要的一点;
目前我们的 ListView 运行效率是很低的,因为在 PersonAdapter 的 getView() 方法中,每次都将布局重新加载了一遍;
当 ListView 快速滚动的时候,这就会成为性能的瓶颈;
仔细观察你会发现,getView() 方法中有一个 convertView 参数;
这个参数用于将之前加载好的布局进行缓存,以便之后可以重用。
修改 PersonAdapter 中的 getView() 代码,如下所示:
public class PersonAdapter extends ArrayAdapter<Person> { ...... @NonNull
@Override
public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
Person person = getItem(position);//获取当前项的 Person 实例
View view;
if (convertView == null) {
view = LayoutInflater.from(context).inflate(resource, parent, false);
} else {
view = convertView;
} ImageView img = view.findViewById(R.id.person_img);
TextView name = view.findViewById(R.id.person_name); img.setImageResource(person.getImgId());
name.setText(person.getName()); return view;
}
}可以看到,现在我们在 getView() 方法中进行了判断,如果 convertView 为 null,则使用 LayoutInflater 去加载布局;
如果不为空,这直接对 convertView 进行重用;
这样就大大提高了 ListView 的运行效率,在快速滚动的时候也可以表现出更好的性能。
不过,目前我们的这份代码还是可以继续优化的;
虽然现在已经不会再重复去加载布局,但是每次在 getView() 方法中还是会调用 View 的 findViewById() 方法来获取一次控件的实例;
我们可以借助 ViewHolder 来对这部分性能进行优化;
修改 PersonAdapter 中的 getView() 代码,如下所示:
public class PersonAdapter extends ArrayAdapter<Person> { private Context context;
private int resource; public PersonAdapter(@NonNull Context context, int resource, @NonNull List<Person> objects) {
super(context, resource, objects);
this.context = context;
this.resource = resource;
} static class ViewHolder {
ImageView img;
TextView name;
} @NonNull
@Override
public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
Person person = getItem(position);//获取当前项的 Person 实例
View view;
ViewHolder viewHolder;
if (convertView == null) {
view = LayoutInflater.from(context).inflate(resource, parent, false);
viewHolder = new ViewHolder();
viewHolder.img = view.findViewById(R.id.person_img);
viewHolder.name = view.findViewById(R.id.person_name);
view.setTag(viewHolder);//将 viewHolder 存储在 View 中
} else {
view = convertView;
viewHolder = (ViewHolder) view.getTag();
}
viewHolder.img.setImageResource(person.getImgId());
viewHolder.name.setText(person.getName()); return view;
}
}我们新增了一个静态内部类 ViewHolder,用于对控件的实例进行缓存。
当 convertView 为 null 的时候,创建一个 ViewHolder 对象,并将控件的实例都存放在 viewHolder 里;
然后调用 view 的 setTag() 方法,将 viewHolder 对象存储在 view 中;
当 convertView 不为 null 时,则调用 view.getTag() 方法,把 viewHolder 重新取出;
这样所有的控件的实例都缓存在了 viewHolder 里,就没有必要每次都通过 findViewById() 方法来获取控件实例了。
另外这个修饰 ViewHolder 的 static,关于是否定义成静态,跟里面的对象数目是没有关系的;
加静态是为了在多个地方使用这个 viewHolder 的时候,类只需加载一次,如果只是使用了一次,加不加也无所谓!
——Berial(B神)原话~
•为 ListView 设置点击事件
修改 ArrayAdapterActivity.java 中的代码,如下所示:
public class ArrayAdapterActivity extends AppCompatActivity { private List<Person> personList;
private ListView listview; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_array_adapter); personList = getData();
PersonAdapter adapter = new PersonAdapter(ArrayAdapterActivity.this, R.layout.person_item, personList); listview = findViewById(R.id.lv_array_adapter);
listview.setAdapter(adapter); listview.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Person person = personList.get(position);
Toast.makeText(ArrayAdapterActivity.this,person.getName()+"被点击了!",Toast.LENGTH_SHORT).show();
}
});
} private List<Person> getData() {
List<Person> list = new ArrayList<>(); Person guanYu = new Person("关羽", R.drawable.guan_yu);
list.add(guanYu); Person sunShangXiang = new Person("孙尚香", R.drawable.sun_shang_xiang);
list.add(sunShangXiang); Person naKeLL = new Person("娜可露露", R.drawable.na_ke_lu_lu);
list.add(naKeLL); return list;
}
}可以看到,我们使用 setOnItemClickListener() 方法为 ListView 注册了一个监听器;
当用户点击了 ListView 中的任何一个子项时,就会调用 onItemClick() 方法;
在这个方法中可以通过 position 参数判断出用户点击的是哪一个子项,然后获取到相应的 Person 实例;
最后通过 Toast 将其显示出来;
•运行效果
Android Studio 通过 ListView 学习 ArrayAdapte的更多相关文章
- 【转】Android Studio安装配置学习教程指南 Gradle基础--不错
原文网址:http://www.linuxidc.com/Linux/2015-02/113890p4.htm 其实很早之前也写了一篇Gradle的基础博客,但是时间很久了,现在Gradle已经更新了 ...
- 【转】Android Studio安装配置学习教程指南 下载和安装--不错
背景 相信大家对Android Studio已经不陌生了,Android Studio是Google于2013 I/O大会针对Android开发推出的新的开发工具,目前很多开源项目都已经在采用,Goo ...
- Android Studio 之 BaseAdapter 学习笔记
•前行必备--ListView的显示与缓存机制 我们知道 ListView.GridView 等控件可以展示大量的数据信息. 假如下图中的 ListView 可以展示 100 条信息,但是屏幕的尺寸是 ...
- Android Studio调试方法学习笔记
(注:本人所用Android Studio的Keymap已设为Eclipse copy) 1.设置断点 只有设置断点,才好定位要调试什么地方,否则找不到要调试的地方,无法调试.(调试过程中也可以增加断 ...
- android studio中ListView与SQLite的结合使用
Da.java public class Db extends SQLiteOpenHelper { public Db(Context context) { super(context, " ...
- Android Studio IDE 简单学习和介绍
@import url(http://i.cnblogs.com/Load.ashx?type=style&file=SyntaxHighlighter.css);@import url(/c ...
- Android studio使用git-android学习之旅(79)
首先我参考了hello_my_show和梦痕_sky的博客,表示感谢 android studio对于git的支持是很好的,这节课我们拉讲解怎么使用git可视化工具来clone project和提交修 ...
- Android Studio 之 ImageView 学习笔记
•参考资料 [1]:菜鸟教程 [2]:bilibili视频教程 •src和blackground的区别 background通常指的都是背景,而src指的是内容 当使用 src 填入图片时,是按照图片 ...
- Android开发学习1----AndroidStudio的安装、创建第一个Android Studio文件、Android Studio界面介绍和HelloWord!
移动开发的工具有很多:Android Studio,eclipse,Hbuilder等,其中,现如今最火的开发工具是Android Studio,Android Studio是谷歌自己推出的一款集成开 ...
随机推荐
- short URL 短网址实现原理剖析
short URL 短网址实现原理剖析 意义,简短便于分享,避免出现超长 URL 的字符长度限制问题 原理分析, 使用 HashMap 存储对应的映射关系 (长度不超过7的字符串,由大小写字母加数字共 ...
- SwiftUI render WKWebView
SwiftUI render WKWebView // // ContentView.swift // webview-app // // Created by 夏凌晨 on 2020/10/27. ...
- CORS All In One
CORS All In One 跨域资源共享 https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS CORS 请求类型 简单请求 预检请求 Ac ...
- user tracker with ETag
user tracker with ETag 用户追踪, without cookies clear cache bug 实现原理 HTTP cache hidden iframe 1px image ...
- project generators & project scaffold
project generators & project scaffold how to write a node cli & Project Scaffold https://www ...
- vue mixin执行覆盖
https://cn.vuejs.org/v2/guide/mixins.html 完整代码 vue-option-overwrite-strategies vue 自带的mixin如果钩子函数重复会 ...
- NGK算力持有好处多多!SPC、VAST等免费拿!
众所周知,NGK是分布式存储的,作为Web3.0以及数字经济时代的基础设施,为数字加密市场带来了全新的商业模式和经济业态,但是,这只是一个重要的起点,真正的价值还在后面! 为了满足NGK生态建设者强烈 ...
- Chateau Renice酒庄 :忠于风味,尊重自然
Chateau Renice酒庄(公司编号:20151318780)凭借优良的葡萄栽培传统.卓越的酿酒技术以及独特风味的葡萄酒,近年来葡萄酒畅销至全球. Chateau Renice酒庄将葡萄酒出口至 ...
- Baccarat流动性挖矿的收益能否持续?该如何参与Baccarat流动性挖矿?
2020年DeFi市场火热,众多投资机构纷纷入场,分享这场资本盛宴.然而,目前市面上大多数DeFi项目手续费高昂,小资金的投资者无法入市.为了让更多的用户参与其中,NGK推出了Baccarat流动性挖 ...
- sql server 局域网与公网上的发布与订阅
一台局域网的服务器,可以访问公网. 一台云端的服务器. 要求:将局域网中的服务器部分数据库同步到云端的服务器上. 配置情况: win server 2012 是发布服务器. win server 20 ...






