Как мне использовать другой макет строки в пользовательском CursorAdapter на основе данных курсора?

Предыстория: я пытаюсь реализовать систему обмена сообщениями в своем приложении и пишу пользовательский CursorAdapter для отображения сообщений в ListView в окне чата. Я хочу использовать другой макет строки для входящих и исходящих сообщений (информация, которая сохраняется в строке SQLite в курсоре). В каждой строке есть одни и те же элементы с одинаковыми идентификаторами, но они расположены по-разному.

Проблема. В настоящее время я переопределил newView() и bindView(). Когда ListView впервые заполняется, он идеально создает все View, проверяя каждую строку, чтобы увидеть, является ли она входящей или исходящей, и раздувает правильный XML-файл. Однако, когда я прокручиваю или в окно добавляется новое сообщение, адаптер повторно использует Views для неправильных строк. Я бы переопределил getView(), но Cursor не передается в качестве параметра, поэтому у меня нет возможности узнать, должна ли строка быть входящей или исходящей.

Я не ищу код, а скорее какое-то предложение по элегантной реализации. Заранее спасибо!


person Glendon Trullinger    schedule 04.06.2011    source источник
comment
Как долго вы ожидаете, что эти списки получат? Если они занимают больше нескольких страниц, отказ от повторного использования просмотров может вызвать проблемы с прокруткой/производительностью.   -  person Austyn Mahoney    schedule 04.06.2011
comment
Они должны поддерживать довольно длинные списки сообщений, поэтому я определенно хотел бы их переработать.   -  person Glendon Trullinger    schedule 04.06.2011


Ответы (2)


Вот два возможных решения:

(1) Используйте единый макет для всех элементов, который можно настроить при привязке для отображения по желанию. Самым простым способом было бы просто иметь корневое представление FrameLayout, которое содержит N дочерних элементов для каждого из различных состояний, и вы делаете одно из них видимым, а все остальные исчезают при привязке. Конечно, вы хотите позаботиться о том, чтобы это не привело к увеличению количества просмотров ваших элементов.

(2) Реализовать Adapter.getItemViewType() http://developer.android.com/reference/android/widget/Adapter.html#getItemViewType(int), чтобы сообщить списковому представлению о различных типах элементов, которые у вас есть, чтобы он повторно использовал правильный.

person hackbod    schedule 04.06.2011
comment
Хотя второй ответ немного расширяет предложение Боба, мне очень нравится ваше первое предложение. Думаю, я пойду по этому пути. Спасибо! - person Glendon Trullinger; 04.06.2011
comment
Для потомков я добился того, чего хотел, создав очень простой двухуровневый макет с тремя дочерними элементами в RelativeLayout. Затем я применяю разные RelativeLayout.LayoutParams к макету в bindView(). - person Glendon Trullinger; 03.07.2011

Всего несколько соображений, я лично нахожу всю комбинацию ListView и CursorAdapter немного... эээ... это слово раздуто? Было бы проще иметь комбинацию ScrollView/LinearLayout, которая просто добавит соответствующий TextView по запросу?

Но что касается вашего решения, поскольку пользователь, похоже, не может изменить порядок сообщений по мере их добавления, вы можете добавить поле ArrayList<String> к своему пользовательскому CursorAdapter, которое будет отслеживать входящие или исходящие сообщения. Что-то вроде:

private ArrayList<String> cursorMonitor; //"incoming" and "outgoing" as your options.

... а затем внутри, где бы ни заполнялся ListView, просто используйте

cursorMonitor.add(my_cursor.getString("outgoing_or_incoming"));

А затем в getView() вы можете переопределить его и использовать cursorMonitor, чтобы определить, какой макет вам нужно раздуть.

person Bob    schedule 04.06.2011