sweetyy、

导航

安卓ListView三种Adapter实践

安卓ListView三种Adapter实践

一、ArrayAdapter

1、创建活动:Array

2、在资源文件 strings.xml 中定义 string-array,使用数组存储数据

<resources>
    <string name="app_name">My Application5</string>

    <string-array name="arrayitem">
        <item>新闻</item>
        <item>财经</item>
        <item>科技</item>
        <item>体育</item>
        <item>娱乐</item>
        <item>汽车</item>
        <item>博客</item>
        <item>读书</item>
        <item>新闻</item>
        <item>财经</item>
        <item>科技</item>
        <item>体育</item>
        <item>娱乐</item>
        <item>汽车</item>
        <item>博客</item>
        <item>读书</item>
        <item>新闻</item>
        <item>财经</item>
        <item>科技</item>
        <item>体育</item>
        <item>娱乐</item>
        <item>汽车</item>
        <item>博客</item>
        <item>读书</item>
    </string-array>
</resources>

3、在布局中添加 ListView 控件:

<?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"
    tools:context=".Array">

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

4、在 MainActivity.Java 中设置布局中 ListView 的 Adapter:

package com.example.myapplication5;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;

import android.app.Dialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.Toast;

public class Array extends AppCompatActivity
{

    private ListView lv;//定义私有变量

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_array);

        lv = (ListView) findViewById(R.id.arrlv);//绑定列表id
        //获取strings里面的item信息
        final String[] list1;//final需定义在方法内,因为listener使用了内部类,内部类不知道外部方法的变量

        list1 = getResources().getStringArray(R.array.arrayitem);//获取strings文件里的内容

        ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, list1);
        //桥接。
        //ArrayAdapter构造方法中参数说明:
                 //contex:当前对象,上下文对象,即要展示ListView的Activity、
                 //布局文件id,ListView中显示的每个列表项的View的资源文件id(simple_list_item_1是官  方模板,系统自带)、
                 //list1:需要显示数据的集合,指定要在列表中显示的数据,可以是数组类型或者List类型的数据。
)

        lv.setAdapter(adapter);//启动适配器

       

        //运行程序,当用户点击ListView中的任何一个子项时,触发OnItemClickListener单击事件监听器,回调监听器的onItemClick()方法对点击事件进行响应,弹出Toast消息。
        lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                Toast.makeText(Array.this, "你点击的是" + list1[position], Toast.LENGTH_LONG).show();
            }
        });
    }
}

5、效果

二、SimpleAdapter

1、创建活动:Simple

2、数据准备(Simple活动中实现),准备Listview所要显示的数据,通常用HashMap或JavaBean对复杂数据进行封装。

//定义一个HashMap构成的列表以键值对的方式存放数据
private ArrayList<HashMap<String,Object>> getData()
{
    ArrayList<HashMap<String,Object>> list = new ArrayList<HashMap<String, Object>>();
    HashMap<String,Object> map = new HashMap<String, Object>();
    map.put("title","兔兔1");
    map.put("info","兔兔吃西瓜,西瓜又大又甜真好吃。");
    map.put("thumb",R.drawable.t1);
    list.add(map);

    map = new HashMap<String, Object>();
    map.put("title","兔兔2");
    map.put("info","两只兔兔一起玩,蹦蹦跳跳真可爱");
    map.put("thumb",R.drawable.t2);
    list.add(map);

    map = new HashMap<String, Object>();
    map.put("title","兔兔3");
    map.put("info","小白兔,爱吃胡萝卜,吃了一根又一根。");
    map.put("thumb",R.drawable.t3);
    list.add(map);

    map = new HashMap<String, Object>();
    map.put("title","兔兔4");
    map.put("info","灰色的兔兔看着毛绒绒");
    map.put("thumb",R.drawable.t4);
    list.add(map);

    map = new HashMap<String, Object>();
    map.put("title","兔兔5");
    map.put("info","兔兔在地上,爬啊爬啊爬啊。");
    map.put("thumb",R.drawable.t5);
    list.add(map);

    map = new HashMap<String, Object>();
    map.put("title","兔兔6");
    map.put("info","一只像小猪的兔兔。");
    map.put("thumb",R.drawable.t6);
    list.add(map);

    map = new HashMap<String, Object>();
    map.put("title","兔兔1");
    map.put("info","兔兔吃西瓜,西瓜又大又甜真好吃。");
    map.put("thumb",R.drawable.t1);
    list.add(map);

    map = new HashMap<String, Object>();
    map.put("title","兔兔2");
    map.put("info","两只兔兔一起玩,蹦蹦跳跳真可爱");
    map.put("thumb",R.drawable.t2);
    list.add(map);

    map = new HashMap<String, Object>();
    map.put("title","兔兔3");
    map.put("info","小白兔,爱吃胡萝卜,吃了一根又一根。");
    map.put("thumb",R.drawable.t3);
    list.add(map);

    map = new HashMap<String, Object>();
    map.put("title","兔兔4");
    map.put("info","灰色的兔兔看着毛绒绒");
    map.put("thumb",R.drawable.t4);
    list.add(map);

    map = new HashMap<String, Object>();
    map.put("title","兔兔5");
    map.put("info","兔兔在地上,爬啊爬啊爬啊。");
    map.put("thumb",R.drawable.t5);
    list.add(map);

    map = new HashMap<String, Object>();
    map.put("title","兔兔6");
    map.put("info","一只像小猪的兔兔。");
    map.put("thumb",R.drawable.t6);
    list.add(map);

    return list;
}

3、准备 ListView 及其子项布局

➢ 在布局文件中加入 ListView 控件

➢ 同时在 layout 目录下定义子项布局文件: listview_item.xml,用于定义列表子项的 View。

(1)activity_simple.xml(Simple活动的布局文件)文件如下:

<?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"
    tools:context=".Simple">

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

(2)listview_item.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">


    <ImageView
        android:id="@+id/thumb1"
        android:layout_width="93dp"
        android:layout_height="168dp"
        android:layout_margin="5dp"
        android:layout_weight="1" />

    <LinearLayout
        android:layout_width="0dp"
        android:layout_height="173dp"
        android:layout_weight="3"
        android:orientation="vertical">

        <TextView
            android:id="@+id/title1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="16sp" />

        <TextView
            android:id="@+id/info1"
            android:layout_width="match_parent"
            android:layout_height="61dp"
            android:textSize="14sp" />
    </LinearLayout>

</LinearLayout>

4、设置Simple.java

(1)数据适配:在Simple.java中创建 SimpleAdapter ,创建适配器,把数据映射到Listview的子项。调用Listview的setAdapter()方法将适配器对象添加到Listview。

simplelv=(ListView)findViewById(R.id.simlv);//绑定列表id
mdata=getData();
String[] map={"title","info","thumb"};
int[] resID = {R.id.title1,R.id.info1,R.id.thumb1};
SimpleAdapter adapter = new SimpleAdapter(this,mdata,R.layout.listview_item,map,resID);
//contex:上下文对象、mdata:带有键值对的数据列表、布局的id、map:键值对的键名、控件的id)
simplelv.setAdapter(adapter);

(2)实现 ListView 的子项点击事件处理。 响应为:用子项的相关信息设置一个弹出对话框

 simplelv.setOnItemClickListener(new AdapterView.OnItemClickListener()
    {
        @Override
        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
            showInfo(position);
        }
    });
}

private void showInfo(int position)
{
    HashMap<String,Object> data = mdata.get(position);
    new AlertDialog.Builder(this)
            .setTitle(data.get("title").toString())
            .setMessage(data.get("info").toString())
            .setPositiveButton("确定", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {

                }
            }).show();
}

5、效果

三、自定义 Adapter

1、创建活动:Base

2、数据准备:同上(Simple中)

3、准备 ListView 及其子项布局

 ①在布局文件中加入 ListView 控件, activity_base.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"
    tools:context=".Base">

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

②在 layout 目录下定义一个带按钮的子项布局文件: listview_bt.xml(一个 ImageView两个 TextView 和一个ImageButton)。listview_bt.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">

    <ImageView
        android:id="@+id/thumb"
        android:layout_width="69dp"
        android:layout_height="149dp"
        android:layout_margin="5dp"
        android:layout_weight="1" />

    <LinearLayout
        android:layout_width="0dp"
        android:layout_height="153dp"
        android:layout_weight="3"
        android:orientation="vertical">

        <TextView
            android:id="@+id/title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="16sp" />

        <TextView
            android:id="@+id/info"
            android:layout_width="match_parent"
            android:layout_height="39dp"
            android:textSize="14sp" />

        <ImageButton
            android:id="@+id/btn"
            android:layout_width="60dp"
            android:layout_height="43dp"
            android:layout_gravity="end"
            android:layout_marginTop="40dp"
            android:background="@android:color/transparent"
            android:src="@drawable/btn" />
    </LinearLayout>

</LinearLayout>

4、在Base.java中进行设置

(3)数据适配:创建自定义 Adapter 并设置

 ① 自定义 MyAdatper 类,继承自 BaseAdapter。并重写其中的 getCount(), getView()等关键方法。
public class MyAdapter extends BaseAdapter//自定义 MyAdatper 类并实现(BaseAdapterDemo 的内部类)
{
    private LayoutInflater mInflater;
    public MyAdapter(Context context) {
        super();
        mInflater = LayoutInflater.from(context);
    }

    @Override
    public int getCount() {
        return mdata.size();
    }

    @Override
    public Object getItem(int position) {
        return mdata.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }
  //方法三:自定义内部类,用于对子项控件的实例进行缓存。
        public final class ViewHolder
        {
            public ImageView thumb;
            public TextView title;
            public TextView info;
            public ImageButton btn;
            View wholesView;
        }
        @Override
        public View getView(final int position, View convertView, ViewGroup parent)
        {
            ViewHolder holder = null;
            if(convertView == null) {
                convertView = mInflater.inflate(R.layout.listview_bt, null);

                holder = new ViewHolder();
                holder.thumb = (ImageView) convertView.findViewById(R.id.thumb);
                holder.title = (TextView) convertView.findViewById(R.id.title);
                holder.info = (TextView) convertView.findViewById(R.id.info);
                holder.btn = (ImageButton) convertView.findViewById(R.id.btn);
                holder.wholesView = convertView;
                convertView.setTag(holder);
            }
            else
                holder = (ViewHolder) convertView.getTag();

            HashMap<String,Object> data = mdata.get(position);

            holder.thumb.setImageResource((Integer)data.get("thumb"));
            holder.title.setText(data.get("title").toString());
            holder.info.setText(data.get("info").toString());
            holder.btn.setTag(position);
            Log.e("BaseAdapter3",data.get("title").toString()+' '+convertView.toString());
 
         //设置监听器
            holder.btn.setOnClickListener(new View.OnClickListener()
            {
                @Override
                public void onClick(View v) {
                    showInfo(position);
                }
            });
            return convertView;
        }

  //弹出消息
private void showInfo(int position)
{
    HashMap<String,Object> data = mdata.get(position);
    new AlertDialog.Builder(this)
            .setTitle(data.get("title").toString())
            .setMessage(data.get("info").toString())
            .setPositiveButton("确定", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                }
            }).show();
}

②创建 MyAdatper 类的实例,传入数据,并为 ListView 设置适配器。

//创建 MyAdatper 类的实例,传入数据,并为 ListView 设置适配器。
private ArrayList<HashMap<String,Object>> getData()
{
    ArrayList<HashMap<String,Object>> list = new ArrayList<HashMap<String, Object>>();
    HashMap<String,Object> map = new HashMap<String, Object>();
    map.put("title","兔兔1");
    map.put("info","兔兔吃西瓜,西瓜又大又甜真好吃。");
    map.put("thumb",R.drawable.t1);
    list.add(map);

    map = new HashMap<String, Object>();
    map.put("title","兔兔2");
    map.put("info","两只兔兔一起玩,蹦蹦跳跳真可爱");
    map.put("thumb",R.drawable.t2);
    list.add(map);

    map = new HashMap<String, Object>();
    map.put("title","兔兔3");
    map.put("info","小白兔,爱吃胡萝卜,吃了一根又一根。");
    map.put("thumb",R.drawable.t3);
    list.add(map);

    map = new HashMap<String, Object>();
    map.put("title","兔兔4");
    map.put("info","灰色的兔兔看着毛绒绒");
    map.put("thumb",R.drawable.t4);
    list.add(map);

    map = new HashMap<String, Object>();
    map.put("title","兔兔5");
    map.put("info","兔兔在地上,爬啊爬啊爬啊。");
    map.put("thumb",R.drawable.t5);
    list.add(map);

    map = new HashMap<String, Object>();
    map.put("title","兔兔6");
    map.put("info","一只像小猪的兔兔。");
    map.put("thumb",R.drawable.t6);
    list.add(map);

    map = new HashMap<String, Object>();
    map.put("title","兔兔1");
    map.put("info","兔兔吃西瓜,西瓜又大又甜真好吃。");
    map.put("thumb",R.drawable.t1);
    list.add(map);

    map = new HashMap<String, Object>();
    map.put("title","兔兔2");
    map.put("info","两只兔兔一起玩,蹦蹦跳跳真可爱");
    map.put("thumb",R.drawable.t2);
    list.add(map);

    map = new HashMap<String, Object>();
    map.put("title","兔兔3");
    map.put("info","小白兔,爱吃胡萝卜,吃了一根又一根。");
    map.put("thumb",R.drawable.t3);
    list.add(map);

    map = new HashMap<String, Object>();
    map.put("title","兔兔4");
    map.put("info","灰色的兔兔看着毛绒绒");
    map.put("thumb",R.drawable.t4);
    list.add(map);

    map = new HashMap<String, Object>();
    map.put("title","兔兔5");
    map.put("info","兔兔在地上,爬啊爬啊爬啊。");
    map.put("thumb",R.drawable.t5);
    list.add(map);

    map = new HashMap<String, Object>();
    map.put("title","兔兔6");
    map.put("info","一只像小猪的兔兔。");
    map.put("thumb",R.drawable.t6);
    list.add(map);
    return list;
}

5、效果

四、日志观察,对 getView 中的三种实现方法逐一测试

1.方法一

直接把布局文件载入,每一次需要显示一个新出现的列表项时都直接加载布局文件,用于构造列表项View,然后对列表项View进行数据填充并返回。

代码如下:

//方法一:直接将布局文件载入,每一次需要显示一个新出现的列表项时都直接加载布局文件,用于构造列表项 View,
//然后对列表项 View 进行数据填充并返回。当需要显示一个屏幕外的新列表项时,需调用getView()方法,重新加载子项布局文件
@Override
public View getView(int position, View convertView, ViewGroup parent)
{
    View itemview = mInflater.inflate(R.layout.listview_bt,null);
    ImageView img = (ImageView)itemview.findViewById(R.id.thumb);
    TextView title = (TextView)itemview.findViewById(R.id.title);
    TextView info = (TextView)itemview.findViewById(R.id.info);
    ImageButton btn =(ImageButton)itemview.findViewById(R.id.btn);

    HashMap<String,Object> data = mdata.get(position);

    img.setImageResource((Integer)data.get("thumb"));
    title.setText(data.get("title").toString());
    info.setText(data.get("info").toString());
    Log.e("BaseAdapter1",data.get("title").toString()+' '+itemview.toString());
    return itemview;
}

2.方法二

使用参数 convertView 缓存子项布局View,当滑动屏幕时,移出屏幕的 Item 可以被缓存起来,便于复用。当有新的列表项需要进入屏幕时,如果缓存区存在可以复用的Item,便可以直接复用 。只需要绑定要显示的新数据即可快速创建出新的item。

不足:每次构造列表子项都需要调用 findViewById() 获取各子控件引用

代码如下:

//方法二:
        @Override
public View getView(int position, View convertView, ViewGroup parent)
{
    if(convertView == null)
        convertView = mInflater.inflate(R.layout.listview_bt,null);
    ImageView img = (ImageView)convertView.findViewById(R.id.thumb);
    TextView title = (TextView)convertView.findViewById(R.id.title);
    TextView info = (TextView)convertView.findViewById(R.id.info);
    ImageButton btn =(ImageButton)convertView.findViewById(R.id.btn);

    HashMap<String,Object> data = mdata.get(position);

    img.setImageResource((Integer)data.get("thumb"));
    title.setText(data.get("title").toString());
    info.setText(data.get("info").toString());
    Log.e("BaseAdapter2",data.get("title").toString()+' '+convertView.toString());
    return convertView;
}

3.方法三

自定义 ViewHolder 缓存列表项的各子控件,实现对于所有空间对象的保留,使得所有的对象id不必重复获取,item对象会重复利用,往下拉的同时,新的图片和数据项会覆盖之前上方的itemView对象,重新显示在下方。

首先,检查参数convertView,为null时意味着没有可复用的 Itemview,这时需要使用 LayoutInflater 去加载布局,

然后创建ViewHolder对象,将各子控件缓存至ViewHolder,调用setTag()方法,将ViewHolder对象存储在convertView中。

如果参数convertView不为null,则意味着存在可复用的ItemView,可调用getTag()方法,直接将存储在convertView的ViewHolder取出来,无需每次调用getView()方法时都调用findViewById()方法来获取子控件实例,进一步提高了运行时的效率。

最后,getView()方法为ViewHolder中的各子控件绑定数据,设置必要的事件监听器,返回配置好的子项convertView 将用于填充Listview。

代码如下:

//方法三:自定义内部类,用于对子项控件的实例进行缓存。
public final class ViewHolder
{
    public ImageView thumb;
    public TextView title;
    public TextView info;
    public ImageButton btn;
    View wholesView;
}
@Override
public View getView(final int position, View convertView, ViewGroup parent)
{
    ViewHolder holder = null;
    if(convertView == null) {
        convertView = mInflater.inflate(R.layout.listview_bt, null);

        holder = new ViewHolder();
        holder.thumb = (ImageView) convertView.findViewById(R.id.thumb);
        holder.title = (TextView) convertView.findViewById(R.id.title);
        holder.info = (TextView) convertView.findViewById(R.id.info);
        holder.btn = (ImageButton) convertView.findViewById(R.id.btn);
        holder.wholesView = convertView;
        convertView.setTag(holder);
    }
    else
        holder = (ViewHolder) convertView.getTag();

    HashMap<String,Object> data = mdata.get(position);

    holder.thumb.setImageResource((Integer)data.get("thumb"));
    holder.title.setText(data.get("title").toString());
    holder.info.setText(data.get("info").toString());
    holder.btn.setTag(position);
    Log.e("BaseAdapter3",data.get("title").toString()+' '+convertView.toString());

    holder.btn.setOnClickListener(new View.OnClickListener()
    {
        @Override
        public void onClick(View v) {
            showInfo(position);
        }
    });
    return convertView;
}

posted on 2021-11-04 20:28  sweetyy、  阅读(150)  评论(0)    收藏  举报