Android类BaseAdapter中的getItem和getItemId方法的目的是什么?


155

我对这些方法的用途getItem以及getItemIdAndroid SDK中的Adapter类感到好奇。

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

如果您在实践中使用了这些方法,可以举个例子吗?


16
+1个好问题。我想指出的是,getItemId()ArrayAdapter()始终返回-1assert false : "TODO"; return -1;
RDS

Answers:


86

我认为这些方法是访问列表数据的一种更干净的方法。无需通过类似的方式直接访问我的适配器对象,myListData.get(position)只需调用类似的适配器即可adapter.get(position)

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

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

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

例如,如果你有2个部分在列表中(水果和糖果):如果你使用getItem(position)position碰巧在该项目的水果节,比如果你要求,你会收到一个不同的对象getItem(position)position在指向一个项目的糖果部分。然后,您可能会返回某种常量ID值,getItemId(position)该值表示getItem(position)正在返回的数据类型,或者用于instanceof确定您拥有的对象。

除了我刚才提到的以外,我从未觉得我真的需要使用这些方法


7
对于与非SQL相关的适配器,getItemId还会有用途吗?如果是这样,应该退还什么?位置?
Android开发人员

1
该方法的目的或用途主要取决于开发人员,而与数据库驱动的应用程序无关。利用它来创建清晰/可读/可重用的代码。
james 2012年

1
是的,我猜。 getViewgetCountgetViewTypeCount,等是专门为正常显示你的ListView UI使用。其他功能只是帮助创建其他功能,例如在单击某个项目时执行其他操作等。尽管我经常getItem在内部使用getView
james 2012年

1
@NicolasZozol当然,可以安全地执行getItemId,仅返回0Lnull不在任何地方使用它。我看不出有任何明显的理由说明UUID会比longID的某些值更有价值。断开模式?那是什么?
詹姆斯

1
@binnyb:Nicolas的意思是,即使没有网络连接,使用UUID,仍然可以创建有效的唯一ID(例如在您的移动设备上)。
2014年

32

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

简而言之,Android允许您将a附加long到任何ListView项目,就是这么简单。当系统通知您用户选择时,您会收到三个标识变量,以告诉您选择了什么:

  • 对视图本身的引用,
  • 它在列表中的数字位置,
  • long您连接到单个元素。

由您决定这三种方式中哪一种最适合您的具体情况,但您始终可以选择这三种方式。可以将其long视为自动附加到商品的标签,只是它更加简单易读。

关于它通常做什么的误解源于一个简单的约定。getItemId()即使它们实际上没有使用此第三标识,所有适配器也必须提供一个。因此,按照惯例,这些适配器(包括SDK中的许多示例或整个Web)仅position出于单一原因返回:它始终是唯一的。但是,如果适配器返回position,这实际上意味着它根本不希望使用此功能,因为position已经知道了。

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

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

1
很好的解释getItemId()...如果/如果您的自定义适配器中未重写此方法,将会发生什么?
dentex

在基类中被标记为抽象,您必须这样做。当然,除非您覆盖覆盖原始适配器的内容。尝试忽略它,如果Eclipse抱怨,那么您必须这样做。:-)
的Gabor

谢谢。我一直将此方法注释掉而没有警告。我有一个CustomAdapter使用“持有者模式”使用getCount(),getItem(...)和getView(...)扩展ArrayAdapter <CustomListItem>。只是出于好奇...
dentex

是的,您可以这样做,因为ArrayAdapter扩展了BaseAdapter并已经提供了自己的实现。
2014年

有了一个简单的数组,就可以了。但是,例如,当您要显示数据库中的项目时,请考虑另一种情况。然后,您可能会扩展BaseAdapter,并且可以使用此长ID存储数据库密钥。当用户选择某些内容时,您将通过id参数直接获取所选记录的键。例如,您可以立即从数据库中加载它。唯一的问题是您必须使用数字键,因为Android决定使用长号而不是宽号。
2014年

6

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

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

编辑:实际上,它只是返回位置:在这种情况下1


2
不,它会返回-1。这是实现方式assert false : "TODO"; return -1;
rds

5
:随着Android 4.1.1,它返回位置grepcode.com/file/repository.grepcode.com/java/ext/...
emmby

4

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


3
如果您在列表视图上有一个标题并且传递给单击处理程序的位置偏移了一个,则这确实非常有用

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已更改的thouse项目。

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

顺便说一句:如果您希望此方法有效,则需要确保您的hasStableIds()方法返回false;


这是一个有价值的观察,您能否提供一些数据来支持这种选择性更新机制?
Jaime Agudo

为什么要hasStableIds()返回假?在我看来,从同一字符串计算出的哈希码每次都会返回相同的值,根据docs,这是一个稳定的ID 。
大McLargeHuge

考虑使用hashCode可能返回两个字符串为true
htafoya

2

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

什么用途。好吧,由于这些值绑定到列表中的项目,因此您可以在用户单击该项目时提取它们。这些值可通过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);
    }
});
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.