AdapterView是一个抽象类,其派生的子类在用法上十分相似。它继承了ViewGroup,常用的实现类有Spinner、ListView和GridView。其中,Spinner是列表选择框,当需要用户选择的时候,可以提供一个列表将所有可选项列出来,供用户选择;ListView以垂直列表的形式显示所有列表项;GridView用于在界面上按行和列分布的方式来显示多个组件。
Adapter接口及其实现类中,Adapter是一个接口,其派生了ListAdapter和SpinnerAdapter两个子接口。ListAdapter为AbsListView提供列表项,而SpinnerAdapter为AbsSpinner提供列表项。常用的实现类有ArrayAdapter、SimpleAdapter和SimpleCursorAdapter等。其中ArrayAdapter通常用于将数组或List集合的多个值包装成多个列表项;SimpleAdapter用于将List集合的多个对象包装成多个列表项;SimpleCursorAdapter与SimpleAdapter类似,但它与数据库打交道。
Base Adapter是一个抽象类,通常用于被继承,可以对个列表项进行最大限度的定制。
以下是一些示例代码:
ArrayAdapter示例代码:
```java
ArrayAdapter
adapter.add("Item 1");
adapter.add("Item 2");
adapter.add("Item 3");
listView.setAdapter(adapter);
```
SimpleAdapter示例代码:
```java
SimpleAdapter
listView.setAdapter(adapter);
```
SimpleAdapter 是一个用于在 Android 应用中显示数据列表的适配器。它接收五个参数,分别是:
1. context:整个应用的上下文,用于获取资源和创建视图等操作。
2. data:一个 List> 类型的集合对象,集合中每个 Map<String, ?> 对象生成一个列表项。
3. resource:界面布局 Id,代表一个布局样式文件,该文件作为列表项的组件,控制列表项的外观。
4. from:一个 String[] 类型的参数,该参数决定提取 Map<String, ?> 对象中哪些 key 对应的 value 来生成列表项。
5. to:一个 int[] 类型的参数,该参数决定使用自定义布局中的哪些 View 组件来组合成一个列表项(数组里面的 id 是自定义布局中各个控件的 id,顺序需要与上面的 from 中的顺序对应)。
BaseAdapter 是 Android 中用于为列表提供数据的适配器基类。继承 BaseAdapter 时,必须重写它的四个方法,分别是:
1. getCount():返回 adapter 中数据的个数,即返回列表项的行数。
2. getItem(int position):获得相应数据集合中特定位置的数据项,即返回当前 Item 显示的数据。
3. getItemId(int position):返回 Item 的 Id。
4. getView(int position, View convertView, ViewGroup parent):每一个 Item 项创建时被调用(即每一次 Item 从屏幕外滑进屏幕内的时候调用,或者程序刚开始的时候创建第一屏 Item 的时候调用)。
Adapter 是 Android 中用于为列表提供数据的适配器接口。ViewAdapter 是 Adapter 的一个实现类,用于将数据绑定到具体的视图上。Spinner (列表选择框)是一种常见的列表展示方式,当需要用户选择的时候,可以提供一个列表将所有可选项列出来,供用户选择。
Spinner 的列表项数据的获取方法有两种,一是直接在 XML 布局文件中为 android:entries 属性指定数组作为数据源,二是在代码中通过 AdapterView 的 setAdapter(adapter) 设置。
1. 在 XML 布局中指定数组作为数据源:
首先,在 values 文件下新建一个 arrays.xml 文件,代码如下:
```xml
```
然后,在 XML 布局文件中定义一个 Spinner,代码如下:
```xml
android:id="@+id/spinner" android:layout_width="wrap_content" android:layout_height="wrap_content" android:entries="@array/phone_brand" /> ``` 以下是重构后的代码: ```xml 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="net.monkeychan.spinnertest.MainActivity"> android:layout_width="match_parent" android:layout_height="wrap_content" android:entries="@array/phone_brand" /> `` 您好,当设置为 android:spinnerMode=“dropdown” 时,即为下拉样式。如果需要弹出选择框样式,可以将 spinnerMode 属性设置为 android:spinnerMode=“dialog”。此时可以添加属性 android:prompt,为弹出的选择框添加标题。 以下是 XML 文件布局示例: ```xml android:id="@+id/spinner" android:layout_width="match_parent" android:layout_height="wrap_content" android:entries="@array/spinner_entries" android:prompt="@string/prompt_message" /> ``` ```xml 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="net.monkeychan.spinnertest.MainActivity"> android:layout_width="match_parent" android:layout_height="wrap_content" android:entries="@array/phone_brand" android:spinnerMode="dialog" /> ``` 以下是重构后的内容: ```xml 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="net.monkeychan.spinnertest.MainActivity"> android:layout_width="match_parent" android:layout_height="wrap_content" android:entries="@array/phone_brand" android:spinnerMode="dialog" android:prompt="@string/select_phone_brand" /> ``` 主要的改动有:去掉了不必要的空格和换行符,并将属性值放在一行中。 在提供的代码中,`android:prompt`属性用于设置弹出选择框的标题。需要注意的是,这里只能引用字符串变量,而不能直接写入标题的内容,否则编译时会出错。 要实现这个效果,你可以按照以下步骤操作: 1. 在代码中通过`AdapterView`的`setAdapter(adapter)`方法设置适配器。 2. 创建一个自定义的适配器类,继承自`BaseAdapter`,并实现相应的方法。 3. 在XML文件中布局适配器所需的视图组件。 4. 在代码中实例化适配器对象,并将其设置给`AdapterView`。 下面是一个简单的示例代码: ```java // MainActivity.java import android.os.Bundle; import android.view.View; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.Button; import android.widget.Spinner; import androidx.appcompat.app.AppCompatActivity; public class MainActivity extends AppCompatActivity { private Button mButton; private Spinner mSpinner; private ArrayAdapter @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mButton = findViewById(R.id.button); mSpinner = findViewById(R.id.spinner); mAdapter = new ArrayAdapter<>(this, android.R.layout.simple_spinner_item); mAdapter.add("选项1"); mAdapter.add("选项2"); mAdapter.add("选项3"); mSpinner.setAdapter(mAdapter); mSpinner.setPrompt("请选择"); // 设置弹出选择框的标题 mButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // 点击按钮时触发的选择框显示事件 mSpinner.showDropDown(); } }); } } ``` ```xml xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context=".MainActivity"> ``` ```java import android.os.Bundle; import android.view.View; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.Spinner; import androidx.appcompat.app.AppCompatActivity; public class MainActivity extends AppCompatActivity { private Spinner spinner; private String[] cities = {"北京", "上海", "广州", "深圳"}; private ArrayAdapter @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); spinner = findViewById(R.id.spinner); adapter = new ArrayAdapter<>(this, android.R.layout.simple_spinner_item, cities); adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); spinner.setAdapter(adapter); spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { @Override public void onItemSelected(AdapterView> parent, View view, int position, long id) { String selectedCity = cities[position]; // 在此处处理选中的城市 } @Override public void onNothingSelected(AdapterView> parent) { // 在此处处理没有选中任何城市的情况 } }); } } ``` ```markdownpublic class MainActivity extends AppCompatActivity { private String[] location = { "北京", "广东", "浙江", "四川", "海南", "福建" }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 从布局中获取到 Spinner 的实例 Spinner spinner = (Spinner) findViewById(R.id.spinner); // 创建一个 ArrayAdapter 的对象,并进行初始化 ArrayAdapter android.R.layout.simple_spinner_dropdown_item, location); // 为 Spinner 设置 Adapter spinner.setAdapter(arrayAdapter); } } ``` 上面的代码中我们使用了 ArrayAdapter,实际上也可以使用其他 Adapter,如 SimpleAdapter、扩展 BaseAdapter 等,道理是一样的。 GridView 是用于在界面上按行、列分布的方式来显示多个组件的视图。默认情况下,GridView 只显示一列。如果想要显示多列,需要在 XML 布局文件中为属性 `android:numColumns`,或者在代码中使用 `setNumColumns(int)` 方法指定列数。行数则是动态改变的,无需指定。 值得注意的是,虽然`GridView`和`ListView`都继承自`AbsListView`,但是它们之间存在一些差异。尤其是在数据源方面,`GridView`并没有一个名为`android:entries`的属性,这意味着我们不能直接在XML布局文件中为`GridView`指定数据源。相反,我们需要在代码中通过`AdapterView`的`setAdapter(adapter)`方法来设置。 在本示例中,我们将使用`SimpleAdapter`来实现数据的绑定。以水果为例,我们可以将图片看作水果图片,文字看作水果名称。由于图中有行和列,所以我们可以使用`GridView`来实现。从图中可以看出,总共有3列。以下是相应的XML布局文件代码: ```xml android:id="@+id/grid_view" android:layout_width="match_parent" android:layout_height="match_parent" android:numColumns="3"> ``` 以上代码定义了一个具有3列的`GridView`。要将具体的水果数据绑定到该视图上,我们需要创建一个自定义适配器类并实现其布局和数据填充逻辑。 ```xml xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:gravity="center_horizontal" 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="net.monkeychan.gridviewtest.MainActivity"> android:id="@+id/gridView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:numColumns="3" /> ``` ```java import android.os.Bundle; import android.widget.ImageView; import android.widget.TextView; import androidx.appcompat.app.AppCompatActivity; public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ImageView fruitImage = findViewById(R.id.fruit_image); TextView fruitName = findViewById(R.id.fruit_name); } } ``` 以下是重构后的代码: ```java public class MainActivity extends AppCompatActivity { // 定义一个 int 型数组,用来存放水果对应图片的资源 id private int[] images = {R.drawable.apple_pic, R.drawable.banana_pic, R.drawable.cherry_pic, R.drawable.grape_pic, R.drawable.mango_pic, R.drawable.orange_pic, R.drawable.pear_pic, R.drawable.pineapple_pic, R.drawable.strawberry_pic}; // 定义一个 String 类型的数组,用来存放水果的名称 private String[] names = {"苹果", "香蕉", "樱桃", "葡萄", "芒果", "香橙", "雪梨", "菠萝", "草莓"}; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 创建一个 List 集合,List 集合的元素是 Map List for (int i = 0; i < names.length; i++) { // 创建一个 Map 集合,用来存放水果图片和水果名称 Map listItem.put("images", images[i]); listItem.put("names", names[i]); listItems.add(listItem); } // 1. 从布局中获取到 GridView 的实例 GridView gridView = (GridView) findViewById(R.id.gridView); // 2. 为 GridView 设置适配器 SimpleAdapter simpleAdapter = new SimpleAdapter( this, listItems, R.layout.gridview_item, new String[]{"images", "names", new int[]{R.id.fruit_image, R.id.fruit_name}); gridView.setAdapter(simpleAdapter); } } ``` 在上面的代码中,我们使用了 SimpleAdapter。实际上,也可以使用其他 Adapter,如 ArrayAdapter、扩展 BaseAdapter 等,道理是一样的。 ListView 以垂直列表的形式显示所有列表项。与 Spinner 类似,ListView 的列表项数据的获取方法有两种:一是直接在 XML 布局文件中为 android:entries 属性指定数组作为数据源;二是在代码中通过 AdapterView 的 setAdapter(adapter) 设置。 1. 在 XML 布局中指定数组作为数据源 首先,在 values 文件下新建一个 arrays.xml 文件,代码如下: ```xml ``` 接下来,在 XML 布局文件中定义一个 ListView,代码如下: ```xml android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> android:id="@+id/listview" android:layout_width="match_parent" android:layout_height="wrap_content" /> ``` 请根据以下内容完成重构,并保持段落结构: ```xml 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="net.monkeychan.listviewtest.MainActivity"> android:layout_width="match_parent" android:layout_height="wrap_content" android:entries="@array/phone_brand" /> ``` 2. 在代码中通过 AdapterView 的 setAdapter(adapter) 设置。下面是我们要达到的效果: 注:这次我们使用自定义Adapter。下面我们仍然以水果为例,图片为水果图片,文字为水果名称。 首先,我们需要定义我们自己的Adapter。从图中可以看出,Adapter需要包含文字和图片元素,因此我们可以使用两个List类型的集合来分别存储文字和图片(因为在R.java文件中,图片资源的id是int类型)。下面是自定义Adapter的代码: ```java public class CustomAdapter extends BaseAdapter { private Context context; private List private List public CustomAdapter(Context context, List this.context = context; this.textList = textList; this.imageList = imageList; } @Override public int getCount() { return textList.size(); } @Override public Object getItem(int position) { return null; } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder viewHolder; if (convertView == null) { convertView = LayoutInflater.from(context).inflate(R.layout.item_view, parent, false); viewHolder = new ViewHolder(); viewHolder.textView = (TextView) convertView.findViewById(R.id.text_view); viewHolder.imageView = (ImageView) convertView.findViewById(R.id.image_view); convertView.setTag(viewHolder); } else { viewHolder = (ViewHolder) convertView.getTag(); } viewHolder.textView.setText(textList.get(position)); viewHolder.imageView.setImageResource(imageList.get(position)); return convertView; } static class ViewHolder { TextView textView; ImageView imageView; } } ``` 下面是重构后的代码: ```java public class MyListViewAdapter extends BaseAdapter { private Context mContext; private int mResource; private List private List public MyListViewAdapter(Context context, int resource, List mContext = context; mResource = resource; mText = text; mImage = image; } @Override public int getCount() { return mText.size(); } @Override public Object getItem(int position) { return mText.get(position); } @Override public long getItemId(int position) { return position; } @Nullable // 在方法返回值上添加注解,表示该方法可能返回 null,使用时需要进行判空处理。 @Override public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) { // 注意,外部传进来的布局文件中必须要有 id 为 fruit_image 和 fruit_name 的 ImageView、TextView,否则会出现空指针错误。 if (convertView == null) { // 如果传入的 convertView 为 null,说明当前视图还没有被创建过,需要重新创建。 convertView = LayoutInflater.from(mContext).inflate(mResource, null); // 通过 layoutInflater 将指定的 xmlLayout 文件转换成一个 View 对象。并将该对象赋值给 convertView。 } ImageView imageView = (ImageView) convertView.findViewById(R.id.fruit_image); // 通过 findViewById 从 convertView 这个 viewGroup里面找到对应的控件。并将其赋值给 imageView。这里使用了 Java-style cast,需要注意类型安全问题。如果找不到相应的控件,则会抛出异常。 TextView textView = (TextView) convertView.findViewById(R.id.fruit_name); // 通过 findViewById 从 convertView 这个 viewGroup里面找到对应的控件。并将其赋值给 textView。这里使用了 Java-style cast,需要注意类型安全问题。如果找不到相应的控件,则会抛出异常。 imageView.setImageResource(mImage.get(position)); // 根据当前位置设置图片资源。注意位置从0开始计数。如果当前位置大于等于列表大小,则会越界。如果越界了就会导致程序出现异常。在实际开发中应该避免这种情况的发生。 textView.setText(mText.get(position)); // 根据当前位置设置文本内容。同样注意位置从0开始计数。如果当前位置大于等于列表大小,则会越界。如果越界了就会导致程序出现异常。在实际开发中应该避免这种情况的发生。 return convertView; // 最后返回这个 View。此时的 View 可能已经被修改过了。如果是第一次调用该方法,那么返回的 View 就是我们刚创建的 View;如果是重复调用该方法,那么返回的就是之前已经存在的 View。因为在该方法中并没有对 View 做任何修改操作,所以返回的是原 View 也可以正常工作。 XML 布局文件: ```xml 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="net.monkeychan.listviewtest.MainActivity"> android:id="@+id/listView" android:layout_width="match_parent" android:layout_height="wrap_content" /> ``` 自定义样式文件(假设为 listitem.xml): ```xml ``` ```java import android.os.Bundle; import android.view.View; import android.widget.ImageView; import android.widget.TextView; import androidx.appcompat.app.AppCompatActivity; public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ImageView fruitImage = findViewById(R.id.fruit_image); TextView fruitName = findViewById(R.id.fruit_name); } } ``` public class MainActivity extends AppCompatActivity { // 定义一个 int 型数组,用来存放水果图片的 id,图片文件放在 drawable 文件夹下 private int[] images = {R.drawable.apple_pic, R.drawable.banana_pic, R.drawable.cherry_pic, R.drawable.grape_pic, R.drawable.mango_pic, R.drawable.orange_pic, R.drawable.pear_pic, R.drawable.pineapple_pic, R.drawable.strawberry_pic, R.drawable.watermelon_pic}; // 定义一个 String 类型数组,用来存放水果名称 private String[] names = {"苹果", "香蕉", "樱桃", "葡萄", "芒果", "香橙", "雪梨", "菠萝", "草莓", "西瓜"}; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 从布局中获取到 ListView 的实例 ListView listView = (ListView) findViewById(R.id.listView); // 创建一个 List List for (int i = 0; i < images.length; i++) { imagesList.add(images[i]); } // 创建一个 List List for (int i = 0; i < names.length; i++) { namesList.add(names[i]); } // 创建一个 MyListViewAdapter 的对象,并进行初始化 MyListViewAdapter myListViewAdapter = new MyListViewAdapter(this, R.layout.listview_item, imagesList, namesList); // 为 ListView 设置 Adapter listView.setAdapter(myListViewAdapter); } } 在上述代码中,我们使用了自定义的Adapter。实际上,除了自定义Adapter外,还可以使用其他类型的Adapter,例如ArrayAdapter或者扩展BaseAdapter等,其原理是相同的。 自定义Adapter的优化——提升AdapterView的运行效率 以上面的ListView为例,我们自定义了一个Adapter。让我们来看一下我们的getView()方法: ```java @Override public View getView(int position, View convertView, ViewGroup parent) { // LayoutInflater,布局加载器,用来加载从外部传进来的布局 convertView = LayoutInflater.from(mContext).inflate(mResource, null); ImageView iv = (ImageView) convertView.findViewById(R.id.fruit_image); TextView tv = (TextView) convertView.findViewById(R.id.fruit_name); iv.setImageResource(mImage.get(position)); tv.setText(mText.get(position)); return convertView; } ``` 之前我们提到过,getView()方法是在每个Item项创建时被调用的。在这个方法中,我们每次都重新加载了一次布局。当我们的Item项数量超出屏幕可显示范围时,如果我们在滑动ListView时来回滑动,实际上是多个Item项在反复创建,同一个布局在反复加载。每一次创建Item项、加载布局都会消耗系统资源,对系统来说是很大的开销。当多次滑动后,可能会导致滑动过程中出现卡顿,给用户带来非常不好的体验。那么,有没有可能将之前已经创建好的Item项和已经加载过的布局缓存起来,当再次使用时,只需从缓存中取出使用,而不用再次创建呢?这就是我们接下来要做的事情。 首先,我们需要对布局进行缓存: 在调用 `getView()` 方法时,我们可以先判断缓存中是否存在布局。如果不存在,才去加载布局。`getView()` 方法中的 `convertView` 参数用于将之前加载好的布局进行缓存,以便进行重用。这样就解决了布局缓存的问题。但是,在 `getView()` 方法中,我们每次都会调用 `findViewById()` 方法来获取控件的实例,这部分还可以进一步优化。 其次,我们可以对控件实例进行缓存。为此,我们定义一个名为 `ViewHolder` 的类,它负责缓存控件的实例。当 `convertView` 为空(即缓存中不存在布局)时,我们创建一个 `ViewHolder` 对象,并将控件的实例存储在其中。 下面是改写后的自定义适配器示例代码: ```java public class CustomAdapter extends BaseAdapter { private List dataList; private Context context; private LayoutInflater inflater; public CustomAdapter(Context context, List dataList) { this.context = context; this.dataList = dataList; inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); } @Override public int getCount() { return dataList.size(); } @Override public Object getItem(int position) { return dataList.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(final int position, View convertView, final ViewGroup parent) { ViewHolder viewHolder; if (convertView == null) { // 如果 convertView 为空,表示需要重新加载布局 convertView = inflater.inflate(R.layout.item_layout, parent, false); // 通过 layoutInflater 将 item_layout.xml 布局文件转换为 View 对象 viewHolder = new ViewHolder(); // 在当前类中定义一个静态内部类作为ViewHolder的引用类型 viewHolder.view = convertView.findViewById(R.id.text_view); // 根据指定的视图 ID 从 convertView 中找到对应的控件实例并存储到 viewHolder.view 中 convertView.setTag(viewHolder); // 将 viewHolder 作为标记保存在 convertView 中,方便后续获取和操作控件实例 } else { // 如果 convertView 不为空,表示可以直接使用缓存的布局和控件实例 viewHolder = (ViewHolder) convertView.getTag(); // 从 convertView 中获取之前缓存的 viewHolder 对象 } viewHolder.view.setText(dataList.get(position).getText()); // 根据数据更新视图的内容 return convertView; // 将更新后的 convertView 返回给父布局进行显示 } /** * 实现缓存控件实例的静态内部类 */ static class ViewHolder { TextView view; // 这里假设我们需要缓存的控件是文本视图,可以根据实际情况修改为其他类型的控件实例 } } ``` ```java public class MyListViewAdapter extends BaseAdapter { private Context mContext; private int mResource; private List private List public MyListViewAdapter(Context context, int resource, List mContext = context; mResource = resource; mText = text; mImage = image; } @Override public int getCount() { return mText.size(); } @Override public Object getItem(int position) { return mText.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder viewHolder; //判断convertView是否为空 if (convertView == null) { //LayoutInflater,布局加载器,用来加载从外部传进来的布局 convertView = LayoutInflater.from(mContext).inflate(mResource, null); //创建ViewHolder的对象 viewHolder = new ViewHolder(); //将控件实例存储在ViewHolder中 viewHolder.iv = (ImageView) convertView.findViewById(R.id.fruit_image); viewHolder.tv = (TextView) convertView.findViewById(R.id.fruit_name); //将ViewHolder存储在convertView中,即缓存布局 convertView.setTag(viewHolder); } else { //重新获取ViewHolder viewHolder = (ViewHolder) convertView.getTag(); } viewHolder.iv.setImageResource(mImage.get(position)); viewHolder.tv.setText(mText.get(position)); return convertView; } //创建一个内部类ViewHolder,用来缓存控件实例class ViewHolder{ ImageView iv; TextView tv; } } ``` 您好!AdapterView 和 Adapter 结合使用的步骤如下: 1. 从布局中获取到 AdapterView 的实例,即 findViewById(); 2. 创建适合的 Adapter 对象,并进行初始化(根据 Adapter 的构造方法的参数列表传入对应的参数类型); 3. 为 AdapterView 设置 Adapter; 4. 当自定义 Adapter 时,应注意优化方面的问题。 参考资料: