- <?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="match_parent"> <ImageView android:id="@+id/image_view" android:layout_width="50dp" android:layout_height="60dp" android:layout_margin="6dp" android:src="@drawable/apple"/> <TextView android:id="@+id/name_text_view" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_toRightOf="@id/image_view" android:text="apple" android:textSize="24sp" android:layout_margin="5dp"/> <TextView android:id="@+id/content_text_view" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_toEndOf="@id/image_view" android:layout_below="@id/name_text_view" android:textSize="15sp" android:text="我是一个苹果" android:layout_margin="5dp"/></RelativeLayout>什么是数据适配
下图展示了数据源、适配器、ListView等数据展示控件之间的关系。我们知道,数据源是各种各样的,而ListView所展示数据的格式则是有一定的要求的。数据适配器正是建立了数据源与ListView之间的适配关系,将数据源转换为ListView能够显示的数据格式,从而将数据的来源与数据的显示进行解耦,降低程序的耦合性。这也体现了Android的适配器模式的使用。对于ListView、GridView等数据展示控件有多种数据适配器,本文讲解最通用的数据适配器——BaseAdapter。
- ListView的显示与缓存机制
我们知道,ListView、GridView等控件可以展示大量的数据信息。假如下图中的ListView可以展示100条信息,但是屏幕的尺寸是有限的,一屏幕只能显示下图中的7条。当向上滑动ListView的时候,item1被滑出了屏幕区域,那么系统就会将item1回收到Recycler中,即View缓冲池中,而将要显示的item8则会从缓存池中取出布局文件,并重新设置好item8需要显示的数据,并放入需要显示的位置。这就是ListView的缓冲机制,总结起来就是一句话:需要时才显示,显示完就被会收到缓存。ListView,GridView等数据显示控件通过这种缓存机制可以极大的节省系统资源。
- BaseAdapter
使用BaseAdapter比较简单,主要是通过继承此类来实现BaseAdapter的四个方法:
public int getCount(): 适配器中数据集的数据个数;
public Object getItem(int position): 获取数据集中与索引对应的数据项;
public long getItemId(int position): 获取指定行对应的ID;
public View getView(int position,View convertView,ViewGroup parent): 获取没一行Item的显示内容。
下面通过一个简单示例演示如何使用BaseAdapter。
1. 创建布局文件
activity_main.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">
<ListView
android:id="@+id/id_listView"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
2. 创建 ListView 子布局
list_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="match_parent">
<ImageView
android:id="@+id/image_view"
android:layout_width="50dp"
android:layout_height="60dp"
android:layout_margin="6dp"
android:src="@drawable/apple"/>
<TextView
android:id="@+id/name_text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@id/image_view"
android:text="apple"
android:textSize="24sp"
android:layout_margin="5dp"/>
<TextView
android:id="@+id/content_text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toEndOf="@id/image_view"
android:layout_below="@id/name_text_view"
android:textSize="15sp"
android:text="我是一个苹果"
android:layout_margin="5dp"/>
</RelativeLayout>
Fruit.java
package example.baseadaptertest;
/**
* Created by Administrator on 2018/10/15.
*/
public class Fruit {
public int imageId; // 图片资源
public String name; // 水果名
public String description; // 水果简介
Fruit(int imageId, String name, String description)
{
this.imageId = imageId;
this.name = name;
this.description = description;
}
}
通过此Fruit类,将要显示的数据与ListView的布局内容一一对应,每个Fruit对象对应ListView的一条数据。
MainActivity.java
package example.baseadaptertest;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.ListView;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
ListView listView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
listView = (ListView) findViewById(R.id.id_listView);
List datas = new ArrayList<>();
int[] drawables = {R.drawable.apple, R.drawable.strawberry};
for (int i = 0; i< 20 ; i++)
{
if (i%2 == 0)
datas.add(new Fruit(drawables[0], "苹果", "又大又红又甜"));
else
datas.add(new Fruit(drawables[1], "草莓", "又黄又小又酸"));
}
listView.setAdapter(new FruitAdapter(this, datas));
}
}
4. 创建BaseAdapter (注意看代码注释)
FruitAdapter.java
package example.baseadaptertest;
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 Administrator on 2018/10/15.
*/
public class FruitAdapter extends BaseAdapter {
private List datas; // 数据源
private LayoutInflater inflater; // 布局装载对象
FruitAdapter(Context context, List datas)
{
this.datas = datas;
this.inflater = LayoutInflater.from(context);
}
// 需要显示的数据总量
@Override
public int getCount() {
return datas.size();
}
// 指定索引对应的数据项
@Override
public Object getItem(int position) {
return datas.get(position);
}
// 指定索引对应的数据项ID
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder;
// 没有缓存
if (convertView == null) {
viewHolder = new ViewHolder();
// 只需要将XML转化为View,并不涉及到具体的布局,所以第二个参数通常设置为null
convertView = inflater.inflate(R.layout.list_item, null);
// 对 viewHolder 的值进行赋值
viewHolder.imageView = convertView.findViewById(R.id.image_view);
viewHolder.name = convertView.findViewById(R.id.name_text_view);
viewHolder.description = convertView.findViewById(R.id.content_text_view);
// 通过 setTag 将 convertView 与 viewHolder 关联
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
// 获取对应索引的Fruit对象
Fruit fruit = datas.get(position);
viewHolder.name.setText(fruit.name);
viewHolder.description.setText(fruit.description);
viewHolder.imageView.setImageResource(fruit.imageId);
return convertView;
}
// 用于缓存控件, 三个属性分别对应item布局的三个控件
class ViewHolder{
public ImageView imageView;
public TextView name;
public TextView description;
}
}
5. 总结一下整体步骤
- 创建数据适配器
- 实现相应接口方法
- 创建数据源
- 利用convertView优化布局加载速度
原文地址: 链接在此