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.ListAdapter>
 	 	 	   ↳	android.widget.AbsListView
 	 	 	 	   ↳	android.widget.ListView

3. ListView 控件的属性

属性说明
android:footerDividersEnabled是否在 footerView(表尾) 前绘制一个分隔条,默认为 true
android:headerDividersEnabled是否在 headerView(表头) 前绘制一个分隔条,默认为 true
android:divider设置分隔条,可以用颜色分割,也可以用 drawable 资源分割
android:dividerHeight设置分隔条的高度
android:entriesListView 要显示的数据资源

 

表头表尾分割线的设置: 

只能在 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 设置的模板,有好几种

  1. simple_list_item_1

    单独一行的文本框

  2. simple_list_item_2

    两个文本框组成

  3. simple_list_item_checked

    每项都是由一个已选中的列表项

  4. simple_list_item_multiple_choice

    都带有一个复选框

  5. 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" ?>
<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="match_parent"
    android:padding="8dp" 
    android:orientation="vertical" >

    <include  
            android:id="@+id/talk_empty"  
            layout="@layout/listview_empty"/>

    <ListView
        android:id="@+id/listview"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</LinearLayout>

7.2 在 res/layout 目录下新建一个列表项的布局 listview_item.xml

<?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:padding="8dp"
    android:orientation="horizontal">

    <ImageView
        android:id="@+id/avatar"
        android:layout_weight="1" 
        android:layout_width="32dp"
        android:layout_height="32dp"/>

    <TextView
        android:id="@+id/say"
        android:layout_weight="7" 
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:gravity="center_vertical"
        android:textSize="18sp" />

</LinearLayout>

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<TalkBean> mData;

    public TalkAdapter() {}

    public TalkAdapter(LinkedList<TalkBean> 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"?>  
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
              android:orientation="vertical"  
              android:layout_width="match_parent"  
              android:layout_height="match_parent">

    <TextView  
        android:gravity="center"  
        android:textSize="18sp"  
        android:textColor="#333333"  
        android:text="没有可显示的数据"  
        android:layout_width="match_parent"  
        android:layout_height="match_parent"/>

</LinearLayout>

 

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<TalkBean> 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<TalkBean>();
        // 将数据源添加到 适配器 中
        talkAdapter = new TalkAdapter((LinkedList<TalkBean>) mData,MainActivity.this);

        // 将适配器数据 添加到 ListView
        listview.setAdapter(talkAdapter);
    }
}

 

 

 

 

如果数据量一多,就特别卡顿,有时候会导致卡死,是什么原因造成的呢?

是因为 getView() 方法,界面上有多少列就会调用多少次 getView() ,每次都是新 inflate 一个 View,都要进行这个 XML 的解析,这样会 很浪费资源

所以我们要对 Adapter 进行优化,有两个目标:

  1. 复用 convertView

因为界面上有多少个 Item,就要调用 getView() 多少次;

每次都要加载一次 xml

其实这个 convertView 是系统提供给我们的可供服用的 View ,既然可复用,那么只要做一下判断就好

@Override
public 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;
}

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值