【问题标题】:What is the intent of the methods getItem and getItemId in the Android class BaseAdapter?Android 类 BaseAdapter 中方法 getItem 和 getItemId 的意图是什么?
【发布时间】:2011-10-06 09:32:07
【问题描述】:

我很好奇 Android SDK 的 Adapter 类中的方法 getItemgetItemId 的用途。

从描述来看,getItem 似乎应该返回底层数据。因此,如果我有一个名称数组 ["cat","dog","red"] 并使用它创建了一个适配器 a,那么 a.getItem(1) 应该返回“dog”,对吗? a.getItemId(1) 应该返回什么?

如果你在实践中使用过这些方法,你能举个例子吗?

【问题讨论】:

  • +1 很好的问题。我想指出ArrayAdapter() 中的getItemId() 总是返回-1assert false : "TODO"; return -1;

标签: android adapter


【解决方案1】:

我认为这些方法是访问列表数据的一种更简洁的方法。我可以简单地调用像adapter.get(position) 这样的适配器,而不是直接通过myListData.get(position) 访问我的适配器对象。

getItemId 也是如此。通常,当我想根据列表中对象的唯一 ID 执行某些任务时,我会使用此方法。这在使用数据库时特别有用。返回的id 可能是对数据库中对象的引用,然后我可以对其执行不同的操作(更新/删除/等)。

因此,您可以使用adapter.getItemId(position),而不是像myListData.get(position).getId() 这样从原始数据对象访问ID。

我觉得需要使用这些方法的一个例子是在一个使用SeparatedListViewAdapter 的项目中。此适配器可以包含多种不同类型的适配器,每个适配器代表不同类型的数据(通常)。在SeparatedListViewAdapter 上调用getItem(position) 时,返回的对象可能会有所不同,具体取决于您发送它的位置。

例如,如果您的列表中有 2 个部分(水果和糖果):如果您使用 getItem(position)position 恰好位于 fruit 部分中的一个项目上,您会收到与您请求 getItem(position) 时不同的对象,其中 position 指向 candy 部分中的项目。然后,您可能会在 getItemId(position) 中返回某种常量 ID 值,它表示 getItem(position) 返回的数据类型,或者使用 instanceof 来确定您拥有的对象。

除了我提到的以外,我从来没有觉得我真的需要使用这些方法

【讨论】:

  • 对于非sql相关的适配器,getItemId还有用吗?如果是这样,应该返回什么?位置?
  • 该方法的目的或使用主要取决于开发人员,与数据库驱动的应用程序无关。使用它来创建清晰/可读/可重用的代码。
  • 是的,我猜。 getViewgetCountgetViewTypeCount 等专门用于正确显示您的列表视图 UI。其他功能只是帮助创建实现其他功能,例如在单击项目时执行进一步的操作等。虽然我经常在getView 中使用getItem
  • @NicolasZozol 当然——不实现getItemId 是安全的,只需返回0Lnull 并且不要在任何地方使用它。我看不出有什么明显的理由说明 UUID 比 ID 的 long 值更有价值。断线模式?那是什么?
  • @binnyb:Nicolas 的意思是,使用 UUID,即使没有网络连接,仍然可以创建有效的唯一 ID(例如在您的移动设备上)。
【解决方案2】:

嗯,看来这个问题可以用更简单直接的方式来回答……:-)

简单地说,Android 允许您将long 附加到任何ListView 项目,就这么简单。当系统通知您用户选择时,您会收到 三个 识别变量来告诉您选择了什么:

  • 对视图本身的引用,
  • 它在列表中的数字位置,
  • long 附加到各个元素。

您可以决定这三个中的哪一个在您的特定情况下最容易处理,但您始终可以从所有三个中进行选择。将此long 视为自动附加到项目的标签,只是它更简单,更容易读取。

对它通常做什么的误解源于一个简单的约定。所有适配器都必须提供getItemId(),即使它们实际上并未使用这第三个标识。因此,按照惯例,这些适配器(包括 SDK 中的许多示例或网络上的所有适配器)只是返回 position,原因只有一个:它始终是唯一的。不过,如果适配器返回position,这确实意味着它根本不想使用这个功能,因为无论如何position 是已知的。

因此,如果您需要返回您认为合适的任何其他值,请随时这样做:

@Override
public long getItemId(int position) {
  return data.get(position).Id;
}

【讨论】:

  • 对此getItemId() 的很好解释...当/如果此方法未在您的自定义适配器中覆盖时会发生什么?
  • 在基类中被标记为抽象,你必须这样做。当然,除非你覆盖了覆盖原始适配器的东西。试着把它排除在外,如果 Eclipse 抱怨,那么你必须这样做。 :-)
  • 谢谢。我总是在没有警告的情况下将这种方法注释掉。我有一个 CustomAdapter extends ArrayAdapter 与 getCount()、getItem(...) 和 getView(...),使用“持有人模式”。只是出于好奇...
  • 是的,您可以这样做,因为 ArrayAdapter 扩展了 BaseAdapter 并且已经提供了自己的实现。
  • 使用简单的数组就可以了。但是请考虑另一种情况,例如,当您想要显示数据库中的项目时。然后您可能会扩展 BaseAdapter 并且可以使用这个长 ID 来存储数据库密钥。当用户选择某些东西时,您将通过 id 参数直接取回所选记录的键。例如,您可以立即从数据库中加载它。唯一的问题是您必须使用数字键,因为 Android 决定使用 long 而不是更广泛的东西。
【解决方案3】:

getItemId 方法主要设计用于与 SQLite 数据库支持的游标一起使用。它将返回位置 1 中项目的底层光标的 id 字段。

在您的情况下,位置 1 中的项目没有 id:我假设 ArrayAdapter 的实现只返回 -1 或 0。

编辑:实际上,它只是返回位置:在本例中为1

【讨论】:

【解决方案4】:

如果你正确实现getItemId,那么它可能会非常有用。

例子:

你有一个专辑列表:

class Album{
     String coverUrl;
     String title;
}

然后你像这样实现getItemId

@Override
public long getItemId(int position){
    Album album = mListOfAlbums.get(position);
    return (album.coverUrl + album.title).hashcode();
}

现在您的项目 ID 取决于 coverUrltitle 字段的值,如果您更改然后在适配器上调用 notifyDataSetChanged(),那么适配器将调用 getItemId () 方法并只更新 id 已更改的项目。

如果在您的 getView() 中执行一些“繁重”操作,这将非常有用。

顺便说一句:如果你想让它工作,你需要确保你的 hasStableIds() 方法返回 false;

【讨论】:

  • 这是一个很有价值的观察,你能提供一些数据来支持这种选择性更新机制吗?
  • 为什么hasStableIds() 应该返回false?在我看来,从同一字符串计算的哈希码每次都会返回相同的值,根据the docs,这是一个稳定的 ID。
  • 考虑使用 hashCode 可能对两个字符串返回 true
【解决方案5】:

我想提一下,在实现getItemgetItemId 之后,您可以使用ListView.getItemAtPositionListView.getItemIdAtPosition 直接访问您的数据,而不是通过适配器。这在实现 onClick 侦听器时可能特别有用。

【讨论】:

  • 如果您的列表视图上有一个标题并且传递给点击处理程序的位置偏离了一个,这确实非常有用
【解决方案6】:

getItemgetItemId 是少数几种主要用于附加数据与列表中的项目的方法。对于getItem,您可以传递将附加到列表中项目的任何对象。通常人们会返回nullgetItemId 是任何唯一的 long 值,您可以将其附加到列表中的相同项目中。人们通常会返回列表中的位置。

有什么用。好吧,由于这些值绑定到列表中的项目,您可以在用户单击项目时提取它们。这些值可通过AdapterView 方法访问。

// template class to create list item objects
class MyListItem{
    public String name;
    public long dbId;

    public MyListItem(String name, long dbId){
        this.name = name;
        this.dbId = dbId;
    }
}

///////////////////////////////////////////////////////////

// create ArrayList of MyListItem
ArrayList<MyListItem> myListItems = new ArrayList<MyListItem>(10);

// override BaseAdapter methods
@Override
public Object getItem(int position) {
    // return actual object <MyListItem>
    // which will be available with item in ListView
    return myListItems.get(position);
}

@Override
public long getItemId(int position) {
    // return id of database document object
    return myListItems.get(position).dbId;
}

///////////////////////////////////////////////////////////

// on list item click, get name and database document id
my_list_view.setOnItemClickListener(new AdapterView.OnItemClickListener() {
    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {

        // extract item data
        MyListItem selectedItem = (MyListItem)parent.getItemAtPosition(position);      
        System.out.println("Your name is : " + selectedItem.name);

        // extract database ref id
        long dbId = id;

        // or you could also use
        long dbId = parent.getItemIdAtPosition(position);
    }
});

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-30
    • 2013-11-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多