Android从零开始:了解适配器和适配器视图

适配器视图无处不在,以至于您很难找到不使用它们的流行Android应用程序。 该名称听起来可能不熟悉,但是如果您认为从未见过适配器视图,则可能是错误的。 每次您看到Android应用以列表,网格或堆栈的形式显示用户界面元素时,您都会看到一个适配器视图在起作用。

顾名思义, 适配器视图是一个View对象。 这意味着,您可以将其添加到活动中,就像添加任何其他用户界面小部件一样。 但是,它无法自行显示任何数据。 它的内容始终由另一个对象( 适配器)确定。 在本教程中,我将向您展示如何创建适配器以及如何使用它们来提供不同类型的适配器视图,例如ListViewGridView

1.什么是适配器?

适配器是实现Adapter接口的类的对象。 它充当数据集和适配器视图之间的链接,适配器视图是扩展抽象AdapterView类的类的对象。 数据集可以是任何以结构化方式表示数据的数据。 数组, List对象和Cursor对象是常用的数据集。

适配器负责从数据集中检索数据,并根据该数据生成View对象。 然后,使用生成的View对象填充绑定到适配器的任何适配器视图。

您可以从头开始创建自己的适配器类,但是大多数开发人员选择使用或扩展Android SDK提供的适配器类,例如ArrayAdapterSimpleCursorAdapter 。 在本教程中,我们重点介绍ArrayAdapter类。

2.适配器视图如何工作?

适配器视图可以非常有效地显示大型数据集。 例如, ListViewGridView小部件可以显示数百万个项目,而没有任何明显的滞后,同时保持内存和CPU使用率非常低。 他们是如何做到的? 不同的适配器视图遵循不同的策略。 但是,这通常是大多数人的工作。

  • 它们仅渲染那些已经在屏幕上或将要在屏幕上移动的View对象。 这样,适配器视图消耗的内存可以是恒定的,并且与数据集的大小无关。
  • 它们还使开发人员可以最大程度地减少昂贵的布局膨胀操作,并回收已经移出屏幕的现有View对象。 这样可以保持较低的CPU消耗。

3.创建一个ArrayAdapter

要创建适配器,您需要以下内容:

  • 数据集
  • 资源文件,其中包含生成的View对象的布局

此外,由于ArrayAdapter类只能使用字符串,因此需要确保所生成的View对象的布局至少包含一个TextView小部件。

步骤1:建立资料集

ArrayAdapter类可以同时使用数组和List对象作为数据集。 现在,让我们使用数组作为数据集。

String[] cheeses = {
            "Parmesan",
            "Ricotta",
            "Fontina",
            "Mozzarella",
            "Cheddar"
          };

步骤2:创建资源文件

创建一个新的布局XML文件,其根元素为LinearLayout并将其命名为item.xml 。 将其中的大文本小部件拖放到其中,并将其id属性的值设置为cheese_name 。 布局XML文件应如下所示:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="https://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="@dimen/activity_horizontal_margin">
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textAppearance="?android:attr/textAppearanceLarge"
        android:text="Large Text"
        android:id="@+id/cheese_name" />
</LinearLayout>

步骤3:创建适配器

在您的活动中,使用其构造函数创建ArrayAdapter类的新实例。 作为参数,传递资源文件的名称, TextView的标识符以及对该数组的引用。 现在适配器已准备就绪。

ArrayAdapter<String> cheeseAdapter = 
    new ArrayAdapter<String>(this,
        R.layout.item,
        R.id.cheese_name,
        cheeses
    );

4.创建一个列表

要显示垂直滚动项目列表,可以使用ListView小部件。 要将小部件添加到活动中,可以将其拖放到活动的布局XML文件中,也可以使用Java代码中的其构造函数来创建。 现在,让我们做后者。

ListView cheeseList = new ListView(this);

通常,没有其他用户界面窗口小部件放置在包含ListView的布局内。 因此,将ListView传递给您活动的setContentView()方法,以使其占据整个屏幕。

setContentView(cheeseList);

要将ListView绑定到上一步中创建的适配器,请调用setAdapter()方法,如下所示。

cheeseList.setAdapter(cheeseAdapter);

如果立即运行应用程序,则应该能够以列表的形式查看数组的内容。

具有ArrayAdapter的ListView

5.创建一个网格

要显示垂直滚动的二维项目网格,可以使用GridView小部件。 ListViewGridView都是抽象AbsListView类的子类,它们具有许多相似之处。 因此,如果您知道如何使用另一种,那么您也会知道如何使用另一种。

使用GridView类的构造函数创建一个新实例,并将其传递给您活动的setContentView()方法。

GridView cheeseGrid = new GridView(this);
setContentView(cheeseGrid);

要设置网格中的列数,请调用其setNumColumns()方法。 我将使它成为一个两列的网格。

cheeseGrid.setNumColumns(2);

通常,您需要使用setColumnWidth()setVerticalSpacing()setHorizontalSpacing()方法来调整列的宽度和它们之间的间距。 请注意,这些方法使用像素作为其单位。

cheeseGrid.setColumnWidth(60);
cheeseGrid.setVerticalSpacing(20);
cheeseGrid.setHorizontalSpacing(20);

现在,您可以使用setAdapter()方法将GridView绑定到我们先前创建的适配器。

cheeseGrid.setAdapter(cheeseAdapter);

再次运行您的应用程序以查看GridView外观。

带有ArrayAdapter的GridView

6.添加事件监听器

可以在适配器视图内的项目上侦听单击和长按事件。 作为示例,让我们向GridView添加一个click事件侦听器。

创建实现AdapterView.OnItemClickListener接口的匿名类的新实例,并将其传递给GridView对象的setOnItemClickListener()方法。 Android Studio会自动为接口的onItemClick()方法生成一个存根。 您会注意到,该方法的参数包括一个整数,用于指定列表项的位置。 您可以使用该整数来找出用户单击了数据集中的哪个项目。

下面的代码说明了每次单击GridView的项目时如何将简单消息显示为小吃条。

cheeseGrid.setOnItemClickListener(new AdapterView.OnItemClickListener() {
    @Override
    public void onItemClick(AdapterView<?> adapterView,
                            View view, int position, long rowId) {

        // Generate a message based on the position
        String message = "You clicked on " + cheeses[position];

        // Use the message to create a Snackbar
        Snackbar.make(adapterView, message, Snackbar.LENGTH_LONG)
                .show(); // Show the Snackbar
    }
});

如果您运行该应用程序并单击网格中的任何项目,则屏幕底部将显示一条消息。 请注意,您可以使用相同的代码来侦听ListView内项目的单击事件。

单击项目时显示的小吃店

7.扩展ArrayAdapter

ArrayAdapter只能处理其生成的View对象的布局内的一个TextView小部件。 要扩展其功能,必须对其进行扩展。 但是,在执行此操作之前,让我们创建一个稍微复杂一些的数据集。

假设我们的数据集包含以下类别的对象,而不是字符串:

static class Cheese {
    String name;
    String description;

    public Cheese(String name, String description) {
        this.name = name;
        this.description = description;
    }
}

这是我们将使用的数据集:

Cheese[] cheeses = {
        new Cheese("Parmesan", "Hard, granular cheese"),
        new Cheese("Ricotta", "Italian whey cheese"),
        new Cheese("Fontina", "Italian cow's milk cheese"),
        new Cheese("Mozzarella", "Southern Italian buffalo milk cheese"),
        new Cheese("Cheddar", "Firm, cow's milk cheese"),
};

如您所见, Cheese类包含两个字段, namedescription 。 要在列表或网格中显示两个字段,项目的布局必须包含两个TextView小部件。

创建一个新的布局XML文件,并将其命名为custom_item.xml 。 向其中添加一个大文本和一个小文本小部件。 将第一个小部件的id属性设置为cheese_name ,将第二个小部件的id属性设置为cheese_description 。 现在,布局XML文件的内容应如下所示:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="@dimen/activity_horizontal_margin">
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textAppearance="?android:attr/textAppearanceLarge"
        android:text="Large Text"
        android:id="@+id/cheese_name" />
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textAppearance="?android:attr/textAppearanceSmall"
        android:text="Small Text"
        android:id="@+id/cheese_description" />
</LinearLayout>

ArrayAdapter还必须能够处理两个TextView小部件。 重新访问您的活动,创建一个扩展ArrayAdapter类的新匿名类,并重写其getView()方法。 确保将数组作为参数传递给其构造函数。

ArrayAdapter<Cheese> cheeseAdapter = 
        new ArrayAdapter<Cheese>(this, 0, cheeses) {
            @Override
            public View getView(int position,
                                View convertView,
                                ViewGroup parent) {

            }
        };

getView()方法内部,必须使用position参数作为数组的索引,并从该索引处获取项目。

Cheese currentCheese = cheeses[position];

getView()方法的第二个参数使我们能够重用View对象。 如果您忽略它,则适配器视图的性能将很差。 首次调用getView()方法时, convertViewnull 。 您必须通过膨胀指定列表项布局的资源文件来初始化它。 为此,请使用getLayoutInflater()方法获取对LayoutInflater的引用,然后调用其LayoutInflater inflate()方法。

// Inflate only once
if(convertView == null) {
    convertView = getLayoutInflater()
                    .inflate(R.layout.custom_item, null, false);
}

此时,您可以使用findViewById()获取对布局内的TextView小部件的引用,并调用它们的setText()方法以使用数组中的数据对其进行初始化。

TextView cheeseName = 
    (TextView)convertView.findViewById(R.id.cheese_name);
TextView cheeseDescription = 
    (TextView)convertView.findViewById(R.id.cheese_description);

cheeseName.setText(currentCheese.name);
cheeseDescription.setText(currentCheese.description);

最后,返回convertView以便可以将其用于填充与适配器关联的任何适配器视图。

return convertView;

8.使用视图架

适配器视图反复调用getView()方法以填充自身。 因此,您必须尝试减少在其中执行的操作数量。

在上一步中,您可能已经注意到,即使我们确保列表项的布局仅膨胀一次,每次getView()方法被调用时,都会调用消耗大量CPU周期的findViewById()方法。叫。

为了避免这种情况并提高适配器视图的性能,我们需要将findViewById()方法的结果存储在convertView对象中。 为此,我们可以使用视图持有者对象,该对象仅是可以存储布局中存在的小部件的类的对象。

因为该布局具有两个TextView小部件,所以视图持有者类还必须具有两个TextView小部件。 我已将类命名为ViewHolder

static class ViewHolder{
    TextView cheeseName;
    TextView cheeseDescription;
}

getView()方法中,为布局充气后,现在可以使用findViewById()方法初始化视图持有者对象。

ViewHolder viewHolder = new ViewHolder();
viewHolder.cheeseName =
        (TextView)convertView.findViewById(R.id.cheese_name);
viewHolder.cheeseDescription =
        (TextView)convertView.findViewById(R.id.cheese_description);

要将视图持有者对象存储在convertView ,请使用其setTag()方法。

// Store results of findViewById
convertView.setTag(viewHolder);

现在,每次调用getView() ,都可以使用getTag()方法从convertView检索视图持有者对象,并使用其setText()方法来更新其中的TextView小部件。

TextView cheeseName = 
    ((ViewHolder)convertView.getTag()).cheeseName;
TextView cheeseDescription = 
    ((ViewHolder)convertView.getTag()).cheeseDescription;
    
cheeseName.setText(currentCheese.name);
cheeseDescription.setText(currentCheese.description);

如果现在运行应用程序,则可以看到GridView在每个单元格中显示两行文本。

GridView每项两行文本

结论

在本教程中,您学习了如何创建适配器并使用它来填充各种适配器视图。 您还学习了如何创建自己的自定义适配器。 尽管我们只关注ArrayAdapterListViewGridView类,但是您可以对Android SDK提供的其他适配器和适配器视图使用相同的技术。

Android支持库包含RecyclerView类。 它的行为很像适配器视图,但是它不是AdapterView类的子类。 如果要创建更复杂的列表,尤其是那些使用多个布局文件作为项目的列表,则应考虑使用它。 要了解更多信息,可以参考此Envato Tuts +教程

要了解有关AdapterView类及其子类的更多信息,可以参考其文档

翻译自: https://code.tutsplus.com/tutorials/android-from-scratch-understanding-adapters-and-adapter-views--cms-26646

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值