安卓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;
}
浙公网安备 33010602011771号