适配器(Adpater)在Android发开中占有非常重地位,你可以理解它是一个从“数据源”通向“视图控件”的桥梁,下面一张图非常直观的说明了“数据源”、“适配器”、“视图控件”三者间的关系
Android为我们提供了很多类型的适配器
从中可以看到,我们之前常用ArrayAdpater、SimpleAdpater等类型的适配器,都是继承于BaseAdapter。BaseAdapter是一个抽象类,我们在使用它的使用它的时候,需要自定义一个类继承它并重写它的一些方法,它的特点是具有较高的灵活性。这里我们还是用ListView来作为今天这个小例子的显示控件。
1.因为ListView中每一个Item都是一个视图,所以我们先新建一个Item的布局:
item.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/image"
android:layout_width="60dp"
android:layout_height="60dp"
android:src="@drawable/ic_launcher"
/>
<TextView
android:id="@+id/title"
android:text="标题"
android:textSize="25sp"
android:gravity="center"
android:layout_width="match_parent"
android:layout_height="30dp"
android:layout_toEndOf="@+id/image"
/>
<TextView
android:id="@+id/text"
android:text="内容"
android:textSize="20sp"
android:gravity="center_vertical"
android:layout_width="match_parent"
android:layout_height="30dp"
android:layout_toEndOf="@+id/image"
android:layout_below="@+id/title"
/>
RelativeLayout>
效果:
2.创建一个ItemBean类,它抽象了Item中的所有控件对应的数据源
package com.example.baseadapter_test;
/**
* 将ListView要显示的Item抽象成一个类
*/
public class ItemBean {
public int Item_ImageResId;
public String Item_Title;
public String Item_Text;
public ItemBean(int Item_ImageResId,String Item_Tilie,String Item_Text) {
this.Item_ImageResId = Item_ImageResId;
this.Item_Text = Item_Text;
this.Item_Title = Item_Tilie;
}
}
3.MainActivity
package com.example.baseadapter_test;
import java.util.ArrayList;
import java.util.List;
import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.ListView;
public class MainActivity extends Activity {
private List itemBeansList = new ArrayList();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//创建数据源
for (int i = 0; i < 20; i++) {
itemBeansList.add(new ItemBean(R.drawable.ic_launcher, "我是标题" + i, "我是内容容" + i));
}
//初始化控件
ListView listView = (ListView)findViewById(R.id.listview);
//设置适配器
listView.setAdapter(new MyAdapter(this, itemBeansList));
}
}
4.自定义一个MyAdapter类继承BaseAdapter并重写它的一些方法:
package com.example.baseadapter_test;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
public class MAdpater extends BaseAdapter{
private List itemBeansList;
//LayoutInflater作用是将layout的xml布局文件实例化为View类对象
private LayoutInflater inflater;
public MyAdapter(Context context,List itemBeansList) {
this.itemBeansList = itemBeansList;
inflater = LayoutInflater.from(context);
}
/**
* 返回数据的总数,它的值决定了ListView一共显示多少行
*/
@Override
public int getCount() {
return itemBeansList.size();
}
/**
* 获取数据源中与指定索引对应的数据项
*/
@Override
public Object getItem(int position) {
return itemBeansList.get(position);
}
/**
* 获取在ListView中与指定索引对应的行id
*/
@Override
public long getItemId(int position) {
return position;
}
/**
* 返回每个Item(每一行)的显示内容
*/
@Override
public View getView(int position, View convertView, ViewGroup parent) {
return null;
}
}
今天的重点来了~~!!!这里我要重点的说一下public View getView(......)这个方法,它会直接影响到ListView的性能。
在这之前,我们必须先来了解一下ListView的工作原(摘自http://www.cnblogs.com/xiaowenji/archive/2010/12/08/1900579.html):
1.ListView 针对List中每个item,要求 adapter “给我一个视图” (getView)。
2.一个新的视图(被创建然后)被返回并显示
如果我们要显示很多个item,我们肯定不能一直通过重新创建View并返回,因为这样会极大的消耗内存!怎么办呢?Android中有个叫做Recycler的构件,用来缓存视图,下图是他的工作原理:
(1).如果你有10亿个项目(item),其中只有可见的项目存在内存中,其他的在Recycler中。
(2).ListView先请求一个type1视图(getView)然后请求其他可见的项目。convertView在getView中是空(null)的。
(3).当item1滚出屏幕,并且一个新的项目从屏幕低端上来时,ListView再请求一个type1视图。convertView此时不是空值了,它的值是item1。你只需设定新的数据然后返回convertView,不必重新创建一个视图。
了解了ListView缓存机制后,我们就开始愉快的重写public View getView(......)吧!|_( ̄▽ ̄)_|
重写方式一之“逗比式”:
@Override
public View getView(int position, View convertView, ViewGroup parent) {
//将布局文件转化成View对象
View view = inflater.inflate(R.layout.item, null);
//在已创建的View查找控件
ImageView imageView = (ImageView)view.findViewById(R.id.image);
TextView text = (TextView)view.findViewById(R.id.text);
TextView title = (TextView)view.findViewById(R.id.title);
//将数据添加到控件中
ItemBean bean = itemBeansList.get(position);
imageView.setImageResource(bean.Item_ImageResId);
text.setText(bean.Item_Text);
title.setText(bean.Item_Title);
return view;
}
该方式通过不停的创建View并返回,没有利用到ListView的缓存机制,不但效率低,且非常浪费内存资源,如果你用这钟方式去做开发,我只想说你是个逗比!
重写方式一之“普通式”:
@Override
public View getView(int position, View convertView, ViewGroup parent) {
//判断convertView是否被缓存(如果已经被创建,就直接使用缓存的convertView,不需要重新创建convertView)
if(convertView == null){
//实例化一个布局
convertView = inflater.inflate(R.layout.item, null);
}
ImageView imageView = (ImageView)convertView.findViewById(R.id.image);
TextView text = (TextView)convertView.findViewById(R.id.text);
TextView title = (TextView)convertView.findViewById(R.id.title);
//将数据添加到控件中
ItemBean bean = itemBeansList.get(position);
imageView.setImageResource(bean.Item_ImageResId);
text.setText(bean.Item_Text);
title.setText(bean.Item_Title);
return convertView;
}
该方式充分利用了ListView的缓存特性,极大提升了ListView的性能。。。唉哟~不错哦!