适配器模式的应用:
1.降低程序耦合性
2.容易扩展
BaseAdapter
ListView的显示与缓存机制:需要才显示,显示完就被会受到缓存。
BaseAdapter基本结构
--public int getCount(); 适配器中数据集中数据的个数
--public Object getItem(int position):获取数据集中与指定索引对应的数据项
--public long getItem(int position):获取指定行对应的ID
--public View getView(int position, ViewconverView, ViewGroup parent):获取每一个Item的显示内容
第一步: 创建布局文件 activity_main.xml 创建好了一个简单的listView
创建item布局文件item.xml,其中有一个ImageView 两个 TextView
activity_main.xml
<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=".MainActivity" >
<ListView
android:id="@+id/lv_main"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</RelativeLayout>
item.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<ImageView
android:id="@+id/iv_image"
android:layout_width="60dp"
android:layout_height="60dp"
android:src="@drawable/ic_launcher"/>
<TextView
android:id="@+id/tv_title"
android:layout_width="match_parent"
android:layout_height="30dp"
android:layout_toEndOf="@+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_below="@+id/tv_title"
android:layout_toRightOf="@+id/iv_image"
android:text="content"
android:gravity="center_vertical"
android:textSize="20sp"/>
</RelativeLayout>
效果如图:
第二步:创建一个Bean对象ItemBean,封装item中显示的内容,在主页面MainActivity.java里面创建数据源
ItemBean.java
public class ItemBean {
public int ItemImageResid;
public String Itemtitle;
public String ItemContent;
public ItemBean(int itemImageResid, String itemtitle, String itemContent) {
super();
ItemImageResid = itemImageResid;
Itemtitle = itemtitle;
ItemContent = itemContent;
}
}
package com.example.sr;
import java.util.ArrayList;
import java.util.List;
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
List<ItemBean> itemBeanList = new ArrayList<ItemBean>();
for(int i = 0; i < 20; i++){
itemBeanList.add(new ItemBean(R.drawable.ic_launcher, "我是标题"+i, "我是内容"+i));
}
}
}
MyAdapter.java
package com.example.sr;
import java.util.List;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
public class MyAdapter extends BaseAdapter {
private List<ItemBean> mList;
public MyAdapter(List<ItemBean> list){ //数据源与适配器进行了关联
mList = list;
}
@Override
public int getCount() { //返回ListView需要显示的数据量
// TODO Auto-generated method stub
return mList.size();
}
@Override
public Object getItem(int position) {//获取数据集中与指定索引对应的数据项
// TODO Auto-generated method stub
return mList.get(position);
}
@Override
public long getItemId(int position) {//获取指定行对应的ID
// TODO Auto-generated method stub
return position;
}
@Override
public View getView(int arg0, View arg1, ViewGroup arg2) {//返回每一项的显示内容
// TODO Auto-generated method stub
return null;
}
}
上面最主要的是getView方法,还没有实现,下面介绍getView方法实现的三重境界
1.逗比式
MyAdapter.java
package com.example.sr;
import java.util.List;
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;
public class MyAdapter extends BaseAdapter {
private List<ItemBean> mList;
private LayoutInflater minflater;//布局装载器对象,用于把xml布局文件转化为view
public MyAdapter(Context context, List<ItemBean> list){ //数据源与适配器进行了关联
mList = list;
minflater = LayoutInflater.from(context);//context要使用当前的Adapter的界面对象
}
@Override
public int getCount() { //返回ListView需要显示的数据量
// TODO Auto-generated method stub
return mList.size();
}
@Override
public Object getItem(int position) {//获取数据集中与指定索引对应的数据项
// TODO Auto-generated method stub
return mList.get(position);
}
@Override
public long getItemId(int position) {//获取指定行对应的ID
// TODO Auto-generated method stub
return position;
}
@Override
public View getView(int postion, View convertView, ViewGroup parent) {//返回每一项的显示内容
// TODO Auto-generated method stub
View view = minflater.inflate(R.layout.item, null);
//第一个参数为 需要装载到item.xml布局文件,第二个参数通常写null
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(postion);
imageView.setImageResource(bean.ItemImageResid);
title.setText(bean.Itemtitle);
content.setText(bean.ItemContent);
return view;
}
}
回到MainActivity.java 建立listView与MyAdapter的联系
MainActivity.java
package com.example.sr;
import java.util.ArrayList;
import java.util.List;
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.widget.ListView;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
List<ItemBean> itemBeanList = new ArrayList<ItemBean>();
for(int i = 0; i < 20; i++){
itemBeanList.add(new ItemBean(R.drawable.ic_launcher, "我是标题"+i, "我是内容"+i));
}
//建立listView与MyAdapter的联系
ListView listView = (ListView) findViewById(R.id.lv_main);
listView.setAdapter(new MyAdapter(this, itemBeanList));//第一个参数为context,第二个是数据源
}
}
至此,运行程序,发现listView可以显示我们想要的东西了。
为什么式逗比式呢?listView有缓冲机制,但是在getView无视了缓冲机制,都通过创建一个新的view去设置空间,效率及其低下,完全没有利用到listView的缓存机制。
2. 普通式
修改getView方法
<span style="white-space:pre"> </span>@Override
public View getView(int postion, View convertView, ViewGroup parent) {//返回每一项的显示内容
// TODO Auto-generated method stub
//逗比式开始----------
//View view = minflater.inflate(R.layout.item, null);
//第一个参数为 需要装载到item.xml布局文件,第二个参数通常写null
/*
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(postion);
imageView.setImageResource(bean.ItemImageResid);
title.setText(bean.Itemtitle);
content.setText(bean.ItemContent);
*/
//逗比式结束-----------
//普通式,参数中已经有了一个converView,考虑是否缓存过了,如果缓存过了,可以直接使用
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(postion);
imageView.setImageResource(bean.ItemImageResid);
title.setText(bean.Itemtitle);
content.setText(bean.ItemContent);
return convertView;
}
利用了ListView的缓存特性,如果没有缓存才创建新的View,算入门,但是findViewById依然会浪费大量时间
3. 文艺式(最好的)
创建了一个内部类 ViewHolder ,它与view相关联,并缓存item的组件,这样给item设置内容的时候,不用再去findviewById, 直接在ViewHolder里面取出来就行了。
<span style="white-space:pre"> </span>@Override
public View getView(int postion, View convertView, ViewGroup parent) {//返回每一项的显示内容
// TODO Auto-generated method stub
//逗比式开始----------
//View view = minflater.inflate(R.layout.item, null);
//第一个参数为 需要装载到item.xml布局文件,第二个参数通常写null
/*
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(postion);
imageView.setImageResource(bean.ItemImageResid);
title.setText(bean.Itemtitle);
content.setText(bean.ItemContent);
*/
//逗比式结束-----------
//普通式,参数中已经有了一个converView,考虑是否缓存过了,如果缓存过了,可以直接使用---------
/*
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(postion);
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中
viewHolder.title = (TextView)convertView.findViewById(R.id.tv_title);
viewHolder.content = (TextView)convertView.findViewById(R.id.tv_content);
convertView.setTag(viewHolder);//进行关联,把它的控件保存在viewHolder中,避免了findviewbyid去实例化
}else{
viewHolder = (ViewHolder)convertView.getTag();
}
ItemBean bean = mList.get(postion);
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;
}
不仅利用了ListView的缓存,更通过ViewHolder类来实现显示数据的视图的缓存,避免多次通过findViewById寻找控件,这是最好的方法。
总结:
ViewHolder优化BaseAdapter的思路
--创建Bean对象,用于封装数据
--创建MyAdapter(继承BaseAdapter)在构造方法中初始化用于映射的数据List
--创建ViewHolder类,创建布局映射关系
--判断ConverView,为空则创建,并设置Tag,否则通过tag来取出ViewHolder
--给ViewHolder中的控件设置数据
源代码下载:BaseAdapter的使用