Какова цель методов getItem и getItemId в базовом адаптере Android?

Мне интересно узнать о целях методов getItem и getItemId в класса в Android SDK.

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

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

Ответ 1

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

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

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

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

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

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

Ответ 2

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

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

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

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

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

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

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

Ответ 3

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

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

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

Ответ 4

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

Ответ 5

Если вы правильно реализуете 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().

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

Ответ 6

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);
    }
});