Каково назначение методов getItem и getItemId в классе Android BaseAdapter? - PullRequest
149 голосов
/ 15 июля 2011

Мне любопытно узнать назначение методов getItem и getItemId в классе Adapter в Android SDK.

Из описания кажется, что getItem должен возвращать базовые данные. Итак, если у меня есть массив имен ["cat","dog","red"] и я использую адаптер a, то a.getItem(1) должен вернуть «dog», правильно? Что должен a.getItemId(1) вернуть?

Если вы использовали эти методы на практике, не могли бы вы привести пример?

Ответы [ 6 ]

84 голосов
/ 15 июля 2011

Я вижу эти методы как более чистый подход к доступу к данным моего списка. Вместо прямого доступа к моему объекту адаптера через что-то вроде myListData.get(position) я могу просто вызвать адаптер как adapter.get(position).

То же самое относится и к getItemId. Обычно я использую этот метод, когда хочу выполнить какую-то задачу на основе уникального идентификатора объекта в списке. Это особенно полезно при работе с базой данных. Возвращенное id может быть ссылкой на объект в базе данных, с которым я затем мог бы выполнять различные операции (обновление / удаление / и т. Д.).

Таким образом, вместо доступа к идентификатору из необработанного объекта данных, например myListData.get(position).getId(), вы можете использовать adapter.getItemId(position).

Одним из примеров того, где я чувствовал, что мне нужно было использовать эти методы, был проект, использующий SeparatedListViewAdapter . Этот адаптер может содержать несколько различных типов адаптеров, каждый из которых представляет данные различного типа (как правило). При вызове getItem(position) на SeparatedListViewAdapter возвращаемый объект может отличаться в зависимости от того, в каком «разделе» находится позиция, в которую вы его отправляете.

Например, если в вашем списке есть 2 раздела (фрукты и конфеты): если вы использовали getItem(position) и position оказались на предмете в разделе фрукты , вы получите другой объект, чем если бы вы запросили getItem(position) с position, указывающим на элемент в разделе candy . Затем вы можете вернуть какое-то постоянное значение идентификатора в getItemId(position), которое представляет, какой тип данных getItem(position) возвращает, или использовать instanceof, чтобы определить, какой у вас объект.

Кроме того, что я упомянул, я никогда не чувствовал, что мне действительно нужно использовать эти методы

30 голосов
/ 18 августа 2013

Что ж, похоже, что на этот вопрос можно было бы ответить проще и проще ...: -)

Проще говоря, Android позволяет вам прикрепить long к любому элементу ListView, это так просто.Когда система уведомляет вас о выборе пользователя, вы получаете три идентифицирующие переменные, чтобы сообщить вам, что было выбрано:

  • ссылка на само представление,
  • его числовая позиция в списке:
  • это long, которое вы прикрепили к отдельным элементам.

Вам решать, с каким из этих трех элементов вам легче всего справитьсяв вашем конкретном случае, но у вас есть все три на выбор все время.Думайте об этом long как о теге, автоматически прикрепляемом к элементу, только в том случае, если его еще проще и легче прочитать.

Недопонимание того, что он обычно делает, вытекает из простого соглашения.Все адаптеры должны предоставить getItemId(), даже если они на самом деле не используют эту третью идентификацию.Таким образом, по соглашению, эти адаптеры (включая множество в примерах в SDK или по всему Интернету) просто возвращают position по одной причине: он всегда уникален.Тем не менее, если адаптер возвращает position, это действительно означает, что он вообще не хочет использовать эту функцию, , поскольку position уже известно, так или иначе.

Итак, есливам нужно вернуть любое другое значение, которое вы считаете нужным, не стесняйтесь сделать это:

@Override
public long getItemId(int position) {
  return data.get(position).Id;
}
5 голосов
/ 15 июля 2011

Метод getItemId в основном предназначен для работы с курсорами, поддерживаемыми базами данных SQLite.Он вернет поле идентификатора базового курсора для элемента в позиции 1.

В вашем случае нет идентификатора для элемента в позиции 1. Я предполагаю, что реализация ArrayAdapter просто возвращает -1 или 0.

EDIT: фактически, он просто возвращает позицию: в этом случае 1.

4 голосов
/ 01 сентября 2013

Я хотел бы отметить, что после реализации getItem и getItemId вы можете использовать ListView.getItemAtPosition и ListView.getItemIdAtPosition для прямого доступа к вашим данным, вместо того, чтобы проходить адаптер. Это может быть особенно полезно при реализации прослушивателя onClick.

3 голосов
/ 11 марта 2015

Если вы правильно внедрили 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();
}

Теперь ваш идентификатор элемента зависит от значений полей coverUrl и title , а если вы измените его, вызовите notifyDataSetChanged()на вашем адаптере адаптер будет вызывать метод getItemId () каждого элемента и обновлять только те элементы, идентификатор которых изменился.

Это очень полезно, если вы выполняете некоторые "тяжелые" операциив вашем getView().

Кстати: если вы хотите, чтобы это работало, вы должны убедиться, что ваш метод hasStableIds() возвращает false;

1 голос
/ 24 сентября 2016

getItem или getItemId - это несколько методов, в основном предназначенных для прикрепления данных с элементами в списке.В случае getItem вы можете передать любой объект, который будет прикреплен к элементу в списке.Обычно люди возвращаются null.getItemId - это любое уникальное значение 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);
    }
});
...