数据源(Data Source)的来源是各式各样的而ListView展示数据的格式却是有一定要求的。数据适配器就是建立了数据源和ListView的这样一个适配关系,将数据源的数据转换为ListView能够显示的格式。将数据的来源和数据的显示进行解耦,降低了程序的耦合性,使程序更加容易扩展。ListView的显示和缓存机制:滑出屏幕的显示区域的数据将这个Item回收到View缓存池中,新要显示的Item会从缓存区中取出设置到相应的位置,即需要的时候才显示,显示完后被回收到缓存区中。
一、创建布局文件
(1)在activity_main.xml中添加一个ListView
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.davebobo.baseadapter.MainActivity">
<ListView
android:id="@+id/lv_main"
android:layout_width="match_parent"
android:layout_height="match_parent">
</ListView>
</RelativeLayout>
(2)新建一个Item布局(item.xml)作为ListView每个布局所要显示的内容
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/iv_image"
android:layout_width="60dp"
android:layout_height="60dp"
android:src="@mipmap/ic_launcher"/>
<TextView
android:id="@+id/tv_title"
android:layout_width="match_parent"
android:layout_height="30dp"
android:layout_toRightOf="@+id/iv_image"
android:text="Title"
android:gravity="center"
android:textSize="25sp"/>
<TextView
android:id="@+id/tv_content"
android:layout_width="match_parent"
android:layout_height="30dp"
android:layout_toRightOf="@+id/iv_image"
android:layout_below="@+id/tv_title"
android:text="Content"
android:gravity="center_vertical"
android:textSize="20sp"/>
</RelativeLayout>
二、创建数据源
创建ItemBean类并封装三个属性,通过Bean对象为我们要显示的数据与我们显示数据的Item布局文件形成一一映射关系。
package com.davebobo.baseadapter;
/**
* Created by DaveBobo on 2016/9/26.
*/
public class ItemBean {
public int ItemImageResid;
public String ItemTitle;
public String ItemContent;
public ItemBean(int itemImageResid, String itemTitle, String itemContent) {
ItemImageResid = itemImageResid;
ItemTitle = itemTitle;
ItemContent = itemContent;
}
}
在main方法中创建假数据
package com.davebobo.baseadapter;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
List<ItemBean> itemBeansList = new ArrayList<>();
for (int i=0;i<20;i++){
itemBeansList.add(new ItemBean(R.mipmap.ic_launcher,
"我是标题"+i,
"我是内容"+i));
}
}
}
三、创建数据适配器
创建MyAdapter类继承BaseAdapter,通过LayoutInflater对象将一个xml文件(resource)转换为View
方式一:没有任何优化处理,每次都创建新的View,设置空控件,效率低
方式二:利用ListView的缓存特性,如果没有缓存才创建新的View,但是findViewById依然会浪费大量时间。
方式三:不仅利用ListView的缓存,更通过ViewHolder类来实现显示数据的视图的缓存,避免多次通过findViewById寻找控件。
package com.davebobo.baseadapter;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import java.util.List;
/**
* Created by DaveBobo on 2016/9/26.
*/
public class MyAdapter extends BaseAdapter{
private List<ItemBean> mList;
private LayoutInflater mInflater;
public MyAdapter(Context context,List<ItemBean> list) {
mList = list;
mInflater = LayoutInflater.from(context);//context:要使用当前的Adapter的界面对象 mInflater:布局装载器对象
}
@Override
public int getCount() {
return mList.size();//返回ListView需要显示的数据数量
}
@Override
public Object getItem(int position) {
return mList.get(position);
}
@Override
public long getItemId(int position) {
return position;//返回指定索引对应的数据项
}
//返回每一项的显示内容
@Override
public View getView(int position, View convertView, ViewGroup parent) {
//方式一:没有利用到ListView的缓存机制
// View view = mInflater.inflate(R.layout.item,null);//通过LayoutInflater对象将一个xml文件转换为View
// ImageView imageView = (ImageView) view.findViewById(R.id.iv_image);
// TextView title = (TextView) view.findViewById(R.id.tv_title);
// TextView content = (TextView) view.findViewById(R.id.tv_content);
// ItemBean bean = mList.get(position);//获得第position个ItemBean对象
// imageView.setImageResource(bean.ItemImageResid);
// title.setText(bean.ItemTitle);
// content.setText(bean.ItemContent);
// return view;
//方式二:使用系统提供的convertView 充分利用了ListView的缓存机制避免了重复地去创建convertView对象
//因为通过LayoutInflater对象将xml转换为View时非常耗时耗资源
// if (convertView==null){
// convertView = mInflater.inflate(R.layout.item,null);
// }
// ImageView imageView = (ImageView) convertView.findViewById(R.id.iv_image);
// TextView title = (TextView) convertView.findViewById(R.id.tv_title);
// TextView content = (TextView) convertView.findViewById(R.id.tv_content);
// ItemBean bean = mList.get(position);//获得第position个ItemBean对象
// imageView.setImageResource(bean.ItemImageResid);
// title.setText(bean.ItemTitle);
// content.setText(bean.ItemContent);
// return convertView;
//方式三:
ViewHolder viewHolder;
if (convertView == null){
viewHolder = new ViewHolder();
convertView = mInflater.inflate(R.layout.item,null);
viewHolder.imageView = (ImageView) convertView.findViewById(R.id.iv_image);
viewHolder.title = (TextView) convertView.findViewById(R.id.tv_title);
viewHolder.content = (TextView) convertView.findViewById(R.id.tv_content);
convertView.setTag(viewHolder);//建立ViewHolder与convertView之间的关系
}else {
viewHolder = (ViewHolder)convertView.getTag();//当convertView不为空时,直接通过getTag方法将保存的对象取出来,通过成员变量取出来
}
ItemBean bean = mList.get(position);//获得第position个ItemBean对象
viewHolder.imageView.setImageResource(bean.ItemImageResid);
viewHolder.title.setText(bean.ItemTitle);
viewHolder.content.setText(bean.ItemContent);
return convertView;
}
class ViewHolder{
public ImageView imageView;
public TextView title;
public TextView content;
}
}
回到MainActivity建立ListView与Adapter之间的联系。在onCreate中添加
ListView listView = (ListView) findViewById(R.id.lv_main);
listView.setAdapter(new MyAdapter(this,itemBeansList));
运行模拟器显示为
一些总结:
public int getCount(): 适配器中数据集中数据的个数
public Object getItem(int position): 获取数据集中与指定索引对应的数据项
public long getItemId(int position): 获取指定行对应的ID
public View getView(int position, View convertView, ViewGroup parent): 获取每个Item的显示内容。
ViewHolder优化BaseAdapter思路:
创建Beam对象用于封装数据
在构造方法中初始化用于映射的数据List
创建ViewHolder类,创建布局映射关系
判断convertView,为空则创建,并设置tag,否则通过tag来取出ViewHolder
给ViewHolder中的控件设置数据