Android(安卓)中 ListView 控件的使用
1. ListView 显示原理
ListView显示数据原理实际就是MVC设计模式,如下图所示:
- Model(模型) – 数据集合,用来存储数据组织
- View(视图) – ListView,负责数据显示
- Controller(控制器) - 负责管理Model,并设置要显示的哪个具体数据.
2. ListView 控件继承关系
java.lang.Object ↳android.view.View ↳android.view.ViewGroup ↳android.widget.AdapterView ↳android.widget.AbsListView ↳android.widget.ListView
3. ListView 控件的属性
属性 | 说明 |
---|---|
android:footerDividersEnabled | 是否在 footerView(表尾) 前绘制一个分隔条,默认为 true |
android:headerDividersEnabled | 是否在 headerView(表头) 前绘制一个分隔条,默认为 true |
android:divider | 设置分隔条,可以用颜色分割,也可以用 drawable 资源分割 |
android:dividerHeight | 设置分隔条的高度 |
android:entries | ListView 要显示的数据资源 |
表头表尾分割线的设置:
只能在 Java 中写代码进行设置了,可供我们调用的方法如下
方法 | 说明 |
---|---|
addHeaderView(View v) | 添加headView(表头),括号中的参数是一个View对象 |
addFooterView(View v) | 添加footerView(表尾),括号中的参数是一个View对象 |
addHeaderView(headView, null, false) | 和前面的区别:设置Header是否可以被选中 |
addFooterView(View,view,false) | 和前面的区别:设置 Footer 是否可以被选中 |
4. Adapter 继承关系
几个常用类的使用准则 :
类 | 说明 |
---|---|
BaseAdapter | 抽象类,用得最多的 Adapter |
ArrayAdapter | 支持泛型操作,最简单的 Adapter,只能展现一行文字 |
SimpleAdapter | 同样具有良好扩展性的 Adapter,可以自定义多种效果 |
SimpleCursorAdapter | 用于显示简单文本类型的 ListView,不推荐使用 XXXXX |
5. ArrayAdapter 构造函数的第二个参数
这其实是我们要给 ListView 设置的模板,有好几种
-
simple_list_item_1
单独一行的文本框
-
simple_list_item_2
两个文本框组成
-
simple_list_item_checked
每项都是由一个已选中的列表项
-
simple_list_item_multiple_choice
都带有一个复选框
-
simple_list_item_single_choice
都带有一个单选钮
6. 自定义类继承 BaseAdapter
常用的需要覆盖的方法:
方法 | 说明 |
---|---|
View getView(int position, View convertView, ViewGroup parent) | 获取显示数据集中指定位置的数据的视图 |
int getCount() | 数据集中有多少项目 |
Object getItem(int position) | 获取与数据集中指定位置关联的数据项 |
long getItemId(int position) | 获取与列表中指定位置关联的行 ID |
7. ListView 实现动态增删改查
动态增加数据,要么要删除一些数据,要么要更改一些数据,这时候,我们的 ListView 就要同步更改才对
来源: https://www.twle.cn/l/yufei/android/android-basic-listview-add.html
7.1 activity_main.xml
添加一个 ListView
<?xml version="1.0" encoding="utf-8" ?>
7.2 在 res/layout
目录下新建一个列表项的布局 listview_item.xml
<?xml version="1.0" encoding="utf-8"?>
7.3 在 MainActivity.java
同一目录下新建一个 Bean
类 TalkBean.java
package cn.twle.android.listviewcrud;public class TalkBean { private int avatar_id; private String say; public TalkBean() {} public TalkBean(int avatar_id, String say) { this.avatar_id = avatar_id; this.say = say; } public int getAvatarId() { return avatar_id; } public String getSay() { return say; } public void setAvatarId(int avatarId) { this.avatar_id = avatarId; } public void setSay(String say) { this.say = say; }}
7.4 在 MainActivity.java
目录下新建一个 Adapter
文件 TalkAdapter.java
package cn.twle.android.listviewcrud;import android.widget.BaseAdapter;import android.widget.ImageView;import android.widget.TextView;import android.content.Context;import android.view.View;import android.view.ViewGroup;import android.view.LayoutInflater;import java.util.LinkedList;public class TalkAdapter extends BaseAdapter { private Context mContext; private LinkedList mData; public TalkAdapter() {} public TalkAdapter(LinkedList mData, Context mContext) { this.mData = mData; this.mContext = mContext; } @Override public int getCount() { return mData.size(); } @Override public Object getItem(int position) { return null; } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder holder = null; if(convertView == null){ convertView = LayoutInflater.from(mContext).inflate(R.layout.listview_item,parent,false); holder = new ViewHolder(); holder.avatar = (ImageView) convertView.findViewById(R.id.avatar); holder.say = (TextView) convertView.findViewById(R.id.say); convertView.setTag(holder); }else{ holder = (ViewHolder) convertView.getTag(); } holder.avatar.setImageResource(mData.get(position).getAvatarId()); holder.say.setText(mData.get(position).getSay()); return convertView; } private class ViewHolder{ ImageView avatar; TextView say; }}
7.5 在 res/layout
目录下新建一个 listview_empty.xml
用于在ListView 没有数据的时候,显示说明
需要在 activity_main.xml
包含 listview_empty.xml
<?xml version="1.0" encoding="utf-8"?>
7.5 MainActivity.java
调用 setEmptyView(View) ,但没有数据的时候显示
import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import android.widget.ListView;import android.widget.Toast;import android.widget.AdapterView;import android.view.View;import java.util.LinkedList;import java.util.List;public class MainActivity extends AppCompatActivity { private ListView listview; private TalkAdapter talkAdapter = null; private List mData = null; private int flag = 0; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); listview = (ListView) findViewById(R.id.listview); View listview_empty = findViewById(R.id.talk_empty); listview.setEmptyView(listview_empty); // 但没有 数据时,显示 // 准备数据源 mData = new LinkedList(); // 将数据源添加到 适配器 中 talkAdapter = new TalkAdapter((LinkedList) mData,MainActivity.this); // 将适配器数据 添加到 ListView listview.setAdapter(talkAdapter); }}
如果数据量一多,就特别卡顿,有时候会导致卡死,是什么原因造成的呢?
是因为 getView()
方法,界面上有多少列就会调用多少次 getView()
,每次都是新 inflate 一个 View,都要进行这个 XML 的解析,这样会 很浪费资源
所以我们要对 Adapter
进行优化,有两个目标:
- 复用
convertView
因为界面上有多少个 Item,就要调用 getView()
多少次;
每次都要加载一次 xml
其实这个 convertView
是系统提供给我们的可供服用的 View
,既然可复用,那么只要做一下判断就好
@Overridepublic View getView(int position, View convertView, ViewGroup parent) { if(convertView == null){ convertView = LayoutInflater.from(mContext).inflate(R.layout.list_item,parent,false); }.....
2. 用 ViewHolder
重用组件,不用每次都 `findViewById()
上面的优化只做到了 XML 文件只加载一次,但 convertView.findViewById
还是调用了多次
其实我们的 ListView
中的每一项都是一模一样的布局,能否只调用一次就好?
答案是肯定的,但需要自己定义一个 ViewHolder
类来对这一部分进行性能优化
ViewHolder
其实就是一个静态类
static class ViewHolder{ ImageView img_icon; TextView txt_aName; TextView txt_aSpeak;}
更多相关文章
- 一句话锁定MySQL数据占用元凶
- onCharacteristicChanged 回调问题
- Android(安卓)首页Fragment切换常用姿势
- Handler 总结
- Android(安卓)TextView显示html富文本格式以及Edittext获取带htm
- permission大全及场景的用法
- Android(安卓)display架构分析(一)
- Android(安卓)如何修改自动同步数据的默认开关 M
- android登录界面