您的位置:首页 > 其它

ListView (3) 之适配器 ArrayAdapter/SimpleAdapter/BaseAdapter

2015-04-16 21:20 211 查看

ListView (3) 之适配器 Adapter

ArrayAdapter/SimpleAdapter/BaseAdapter的使用

Android中通过Adapter为AbsListView列表控件提供基础数据,Adapter只是一个接口,它派生了ListAdapter和SpinnerAdapter,其中ListAdapter为AbsListView提供列表,SpinnerAdapter为AbsSpinner提供数据。





ListView、 Adapter、 数据源三者之间的关系图

ArrayAdapter

ArrayAdapter是较为简单快捷的适配器,不需要创建专门的Item布局来填充列表项,通过提供一个String[]类型的数据源,可以直接通过系统自带的布局文件

数据源为String[] 的数据集合

String[] list = { "李阳疯狂英语", "AOC", "BBC", "CCTV", "优酷财经" };
// 将数组包装成ArrayAdapter
ArrayAdapter<String> adapter = new ArrayAdapter<String>(context,android.R.layout.simple_list_item_single_choice, list);
listView.setAdapter(adapter);


ArrayAdapter构造函数,第二个参数为 带有一个TextView系统布局资源ID,TextView的ID为@android:id/text1,点击可查看布局如下

<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@android:id/text1"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:gravity="center_vertical"
    android:minHeight="?android:attr/listPreferredItemHeightSmall"
    android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
    android:paddingStart="?android:attr/listPreferredItemPaddingStart"
    android:textAppearance="?android:attr/textAppearanceListItemSmall" />


数据源保存在资源文件

// 获取resource资源文件定义好的数组
Resources res = getResources();
String[] arrs = res.getStringArray(R.array.books);
// 将数组包装成ArrayAdapter,第二个参数为 带有一个TextView
// 布局资源,TextView的ID为@android:id/text1
ArrayAdapter<String> adapter = new ArrayAdapter<String>(context,android.R.layout.simple_list_item_1, arrs);
listView.setAdapter(adapter);


SimpleAdapter

通过ArrayAdapter实现的Adapter虽然简单、易用,但功能有限,它只能通过每个列表项是TextView,如果需要实现更复杂的列表项,则可以使用SimpleAdapter。SimpleAdapter并非如名字简单,它的功能很强大,可实现ListView的大部分应用。

<?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/Img"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>

    <TextView 
        android:id="@+id/name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_toRightOf="@+id/Img"
        android:gravity="center_vertical"
        android:layout_marginLeft="20sp"/>

    <TextView 
        android:id="@+id/country"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_toRightOf="@+id/name"
        android:layout_marginLeft="20sp"/>

</RelativeLayout>


package com.example.listview03_simpleadapter;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import android.app.Activity;
import android.os.Bundle;
import android.widget.ListView;
import android.widget.SimpleAdapter;

public class MainActivity extends Activity {
    private String[] names = { "姚明", "Kobe", "贝克汉姆", "加索尔" };
    private String[] country = { "中国", "美国", "英国", "西班牙" };
    private int[] imgId = { R.drawable.j1a2, R.drawable.j1a4, R.drawable.j1a5,R.drawable.j1a6 };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // 创建一个List集合,集合元素Map
        List<Map<String, Object>> listItem = new ArrayList<Map<String, Object>>();
        for (int i = 0; i < names.length; i++) {
            Map<String, Object> map = new HashMap<String, Object>();
            map.put("img", imgId[i]);
            map.put("name", names[i]);
            map.put("country", country[i]);
            listItem.add(map);
        }

        // 创建Adapter实例
        SimpleAdapter adapter = new SimpleAdapter(MainActivity.this, listItem,R.layout.item, new String[] { "img", "name", "country" },new int[] { R.id.Img, R.id.name, R.id.country });

        ListView listView = (ListView) findViewById(R.id.listViewId);
        listView.setAdapter(adapter);
    }
}


BaseAdapter使用及优化

【重点】下面重点介绍,BaseAdapter是一个实现了ListAdapter和SpinnerAdapter接口的抽象类,可用于为ListView和Spinner提供数据适配器。

public abstract class BaseAdapter implements ListAdapter, SpinnerAdapter {


关于BaseAdapter的使用,相信一张图足以说明




[图片来源:鸿洋大神的博客]

(/article/1580267.html)

继承自BaseAdapter的自定义适配器

public class MyListAdapter extends BaseAdapter {
    private Context context;

    /** 数据源 */
    private List<User> mList;

    private LayoutInflater inflater;

    public MyListAdapter(Context context, List<User> mList) {
        super();
        this.context = context;
        this.mList = mList;
        inflater = LayoutInflater.from(context);
    }

    @Override
    public int getCount() {
        return mList.size();
    }

    @Override
    public User 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) {

        return null;
    }

}


从上代码片段中可以看到,我们自定义的数据适配器继承子BaseAdapter,需要复写下面四个方法

getCount() —获取数据源个数

getItem(int position) —获取指定position的数据实体

getItemId(int position) —获取数据列表的行编号,一般返回position

getView(int position, View convertView, ViewGroup parent) —此方法最为重要,返回一个显示在数据列表中View;

在getView方法加载指定XML布局文件,设置每个Item显示内容,绑定Item中各个控件的监听事件,具体操作以下代码块

getView方法 convertView的复用

首先,getView的三个参数分别代表: 序号(位置)、列表中一个ITEM的显示视图、view依附的父视图

Android中有个叫做Recycler(反复循环器)的构件,下图是它的工作原理:




convert的复用:一共有200条,每屏可以显示7条数据,初次加载并不会一次性调用200次getView方法,只会调用前7次,生成7个convertView显示到页面上, 当页面滑动第一个Item被划出屏幕外,此时划出屏幕外的Item1存在convertView中,convertView是一个xml资源生成的View,当底部有新的Item划入屏幕,此时convertView持有了划出屏幕外的view,可以拿来直接使用,而减少了inflate资源的次数。也就是说利用convertView的复用,虽然数据源总个数为200,但只有第一次 执行inflate加载xml资源。

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    View view = convertView;
    if (view == null) {
        view = inflater.inflate(R.layout.item_simple, parent, false);
    }
    TextView tvName = (TextView) view.findViewById(R.id.name);
    TextView tvCity = (TextView) view.findViewById(R.id.country);
    tvName.setText(mList.get(position).getName());
    tvCity.setText(mList.get(position).getCountry());
    Log.i("getView", "pos:" + position);
    return view;
}


ViewHolder优化findView次数

从上述代码片中,通过convertView复用减少了inflate加载资源的次数,可每次执行getView方法时,每次通过findViewById去找convertView的所用子控件,在反复滑动时会不断调用getView方法,所以同时就会反复调用findViewById方法。为了提高性能,减少findViewById次数,我们这里就用到了ViewHolder来持有convertView的每一个子控件,以setTag的形式和convertView绑定,需要时再从convertView.getTag()中取出,避免了反复findViewById的情况。

private class ViewHolder {
    public TextView tvName;
    public TextView tvCity;
}


@Override
public View getView(int position, View convertView, ViewGroup parent) {
    View view = convertView;
    if (view == null) {
        ViewHolder viewHolder = new ViewHolder();
        view = inflater.inflate(R.layout.item_simple, parent, false);
        // 通过ViewHolder持有view中的子控件
        viewHolder.tvName = (TextView) view.findViewById(R.id.name);
        viewHolder.tvCity = (TextView) view.findViewById(R.id.country);
        // 再通过setTag的形式和view绑定
        view.setTag(viewHolder);
    }
    ViewHolder viewHolder = (ViewHolder) view.getTag();
    viewHolder.tvName.setText(mList.get(position).getName());
    viewHolder.tvCity.setText(mList.get(position).getCountry());
    return view;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐