Android ListView ArrayAdapter 的简单使用

ArrayAdapter一个具体的BaseAdapter能支持任意数组对象,在默认情况下这类预期提供的资源id引用的是一个TextView.如果你想使用一个更复杂的布局,使用构造函数也需要一个字段id,该字段id应该引用一个TextView在更大的布局资源。然而对TextView的引用,他会对数组里的每个对象进行toString()方法,你可以添加自定义对象的列表或者数组,覆盖你的对象的toString()方法来确定将显示在项目列表中的文本。用一些除了TextView的控件显示数组,例如ImageView,或者有一些数据除了toString()填充视图,需要覆盖getView()返回你想要的类型。

public class ArrayAdapter<T> extends BaseAdapter implements Filterable {} 继承了BaseAdapter 可以调用其中存在的一些属性方法。实现了Filterable,这里不对其做过多的解释。

构造函数:

1、public ArrayAdapter(Context context, int textViewResourceId) {
init(context, textViewResourceId, 0, new ArrayList<T>());
}

2、  public ArrayAdapter(Context context, int resource, int textViewResourceId) {
init(context, resource, textViewResourceId, new ArrayList<T>());
}

3、 public ArrayAdapter(Context context, int textViewResourceId, T[] objects) {
init(context, textViewResourceId, 0, Arrays.asList(objects));
}

4、public ArrayAdapter(Context context, int resource, int textViewResourceId, T[] objects) {
init(context, resource, textViewResourceId, Arrays.asList(objects));
}

5、  public ArrayAdapter(Context context, int textViewResourceId, List<T> objects) {
init(context, textViewResourceId, 0, objects);
}

6、 public ArrayAdapter(Context context, int resource, int textViewResourceId, List<T> objects) {
init(context, resource, textViewResourceId, objects);
}

这六个构造函数其中最多包括的参数有4个,Context 当前上下文,布局文件(可以省略),textView资源id和 数据来源(数组或者集合),同样都调用了一个init()函数。

private void init(Context context, int resource, int textViewResourceId, List<T> objects) {
mContext = context;
mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mResource = mDropDownResource = resource;
mObjects = objects;
mFieldId = textViewResourceId;
}

分别赋值给类中的私有域,mInflater为LayoutInflater,产生相应项的视图。

mResource = mDropDownResource = resource;显示填充视图内容的资源

类中有两个域保存数据

private List<T> mObjects;

private ArrayList<T> mOriginalValues;

其中mOriginalValues用于过滤数据时保存过滤前的数据,将过滤后的数据存入mObjects。
在ArrayAdapter中还定义了add,insert,remove,clear函数用于改变数据,并定义了一个布尔变量mNotifyChange用于表示用这些函数改变数据后是否通知视图(调用notifyDataSetChanged,调用这个函数时会把mNotifyChange置为true。
还定义了createViewFromResource用来创建视图, 在createViewFromResource中,首先判断convertView是否存在,若不存在则inflate一个,然后判断mFieldID是否为0,若为0则表示传递给ArrayAdapter的资源ID为一TextView,否则是传递了一Layout,mFieldID为此Layout中TextView的ID。然后通过getItem取得相应位置的数据项,判断是否是CharSequence的实例,如果是直接setText,否则调用其toString()函数,可以ArrayAdapter默认只能给TextVext设置字符串,若要使用其他视图,需要重载getView或getDropDownView,一般情况下会继承BaseAdapter自定义自己的Adapter。
静态函数
    public static ArrayAdapter<CharSequence> createFromResource(Context context,
int textArrayResId, int textViewResId) {
CharSequence[] strings = context.getResources().getTextArray(textArrayResId);
return new ArrayAdapter<CharSequence>(context, textViewResId, strings);
}

 读取资源文件中定义的字符数组作为数据生成ArrayAdapter,可以看到只能用TextView视图,而不可以指定一Layout再指定Layout中一个TextView的ID。
在ArrayAdapter中还定义了一个ArrayFilter,继承自Filter,用于过滤数据项(当ListView有焦点时,通过键盘输入字符来进行列表项的过滤),其过滤方法为传入一CharSequence,判断相应数据项是否以此CharSequence开头,若不是则用空格分割些数据项,判断分割后的各字符串是否以此CharSequence开头,若是则保留(若数据不是CharSequence则调用其toString())。如果传入的CharSequence为null或长度为0则不过滤。

前面写了3篇关于android的文章,其中的演示程序都写在了一个工程中,当时为了方便测试就在启动页MainActivity中放了3个按钮,点击不同的按钮进入不同的示例程序页面,MainActivity的界面如下截图:

01

按照上面的设计,每写一个演示程序就需要在MainActivity中新增一个按钮并为其写点击事件,感觉这样有点麻烦,于是想改进一下,顺便用一下ListView和ArrayAdapter。经过改进后的启动页如下图:

02

新建了一个MainActivity2,用一个ListView来展现演示程序列表,点击相应列表项就跳转到相应的演示页面,功能和之前的MainActivity一样,但之后就不需要不断添加按钮及其点击事件了,只需要为每个演示页面添加一行代码:catalogs.add(new Catalog("演示的名称", 要跳转到的Activity.class)),这样就简洁多了,具体代码如下。

MainActivity2布局文件如下:

<?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"
    android:orientation="vertical" >

    <ListView
        android:id="@+id/lvCatalog"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent" >
    </ListView>

</LinearLayout>

MainActivity2 Java代码如下:

package chengyujia.demo.aty;

import java.util.ArrayList;
import java.util.List;

import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import chengyujia.demo.R;
import chengyujia.demo.model.Catalog;

public class MainActivity2 extends BaseActivity {

    private ListView lvCatalog;
    private List<Catalog> catalogs;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main2);
        lvCatalog = (ListView) findViewById(R.id.lvCatalog);
        init();
    }

    private void init() {
        catalogs = new ArrayList<Catalog>();
        // 为主页目录添加条目,以后每多写一个例子,在这里添加一个条目就可以了。
        // 不像以前MainActivity中每多写一个例子,需要添加一个按钮,还要写相应的点击事件。
        catalogs.add(new Catalog("屏幕方向", OrientationActivity.class));
        catalogs.add(new Catalog("打电话", CallActivity.class));
        catalogs.add(new Catalog("版本信息", VersionActivity.class));

        // 这里ListView的适配器选用ArrayAdapter,ListView中每一项的布局选用系统的simple_list_item_1。
        ArrayAdapter<Catalog> adapter = new ArrayAdapter<Catalog>(this, android.R.layout.simple_list_item_1, catalogs);
        lvCatalog.setAdapter(adapter);

        // 通过一个实现OnItemClickListener接口的匿名类的onItemClick方法来处理ListView中每一项的点击事件。
        lvCatalog.setOnItemClickListener(new OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                startActivity(new Intent(MainActivity2.this, catalogs.get(position).cls));
            }
        });
    }
}

在这里还使用了一个自定义的Model类Catalog,用来表示列表中的每一项绑定的数据,其代码如下:

package chengyujia.demo.model;

import android.app.Activity;

//主页目录列表项
public class Catalog {

    // 条目名称
    public String name;
    // 点击条目要跳转到的目标Activity的类型
    public Class<? extends Activity> cls;

    // 写个带参数的构造方法,方便赋值使用。
    public Catalog(String name, Class<? extends Activity> cls) {
        this.name = name;
        this.cls = cls;
    }

    // ListView使用ArrayAdapter<T>时每个列表项显示的内容就是T的toString方法返回的值,
    // 如果这里不重写则会调用父类Object的toString方法。
    @Override
    public String toString() {
        return name;
    }
}

Catalog类中注意的是一定要重写toString方法,不然的话ListView的每一项显示的是“对象的类名+@+hashCode”的组合字符串。

来源:https://www.cnblogs.com/chengyujia/archive/2015/12/08/5031323.html