Предложения оптимизации для ListView с данными из нескольких «таблиц»

Я просто столкнулся со следующей ситуацией. У меня есть приложение для Android со сценарием, который, как я предполагаю, может произойти в нескольких приложениях. Речь идет о маркировке / маркировке / классификации, назовите ее по своему усмотрению. Я в основном имею следующие отношения в SQLite DB

-------- -------------- --------- | Tags | | DeviceTags | | Devices | |--------| |--------------| |---------| | ID | 1 ------ * | ID | * ------ 1 | ID | | NAME | | TAGS_ID | | NAME | -------- | DEVICE_ID | | ... | -------------- --------- 

Все открыто через ContentProvider, который я написал. Пока все в порядке.

В части пользовательского интерфейса у меня есть ListActivity, показывающий все сохраненные Устройства (из таблицы Устройства) и для дальнейшей настройки пользовательского интерфейса, я создал настраиваемые элементы строки, показывающие небольшое изображение спереди на основе типа устройства и т. Д.

То, что я хотел бы достичь сейчас, также показать связанные теги в этом списке для каждого устройства. Теперь вот моя проблема . Для простого списка устройств я создал пользовательский ResourceCursorAdapter, где я установил соответствующую информацию в методе bindView

 @Override public void bindView(final View view, final Context context, final Cursor cursor) { final int objectId = cursor.getInt(cursor.getColumnIndex(Devices._ID)); TextView deviceName = (TextView) view.findViewById(R.id.deviceName); deviceName.setText(...); //set it from the cursor ... TextView associatedTagsView = (TextView)...; associatedTagsView.setText(...); //<<<???? This would need a call to a different table ... } 

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

 @Override public void bindView(final View view, final Context context, final Cursor cursor) { ... TextView associatedTagsView = (TextView)view.findViewById(R.id.deviceTags); String tagsString = retrieveTagsString(view.getContext().getContentResolver(), objectId); ... } private String retrieveTagsString(ContentResolver contentResolver, int objectId) { Cursor tagForDeviceCursor = contentResolver.query(DroidSenseProviderMetaData.TABLE_JOINS.TAG_DEVICETAG,...); if(tagForDeviceCursor != null && tagForDeviceCursor.moveToFirst()){ StringBuffer result = new StringBuffer(); boolean isFirst = true; do{ if(!isFirst) result.append(", "); else isFirst = false; result.append(retrieve name from cursor column...); }while(tagForDeviceCursor.moveToNext()); return result.toString(); } return null; } в @Override public void bindView(final View view, final Context context, final Cursor cursor) { ... TextView associatedTagsView = (TextView)view.findViewById(R.id.deviceTags); String tagsString = retrieveTagsString(view.getContext().getContentResolver(), objectId); ... } private String retrieveTagsString(ContentResolver contentResolver, int objectId) { Cursor tagForDeviceCursor = contentResolver.query(DroidSenseProviderMetaData.TABLE_JOINS.TAG_DEVICETAG,...); if(tagForDeviceCursor != null && tagForDeviceCursor.moveToFirst()){ StringBuffer result = new StringBuffer(); boolean isFirst = true; do{ if(!isFirst) result.append(", "); else isFirst = false; result.append(retrieve name from cursor column...); }while(tagForDeviceCursor.moveToNext()); return result.toString(); } return null; } 

Я тестировал это, и на самом деле все работает отлично, но, честно говоря, я не чувствую себя хорошо. Мне почему-то кажется странным …

Есть ли какие-то лучшие решения о том, как это решить?

//Редактировать:

После отзыва CommonsWare здесь немного разъяснений. Я странно отношусь к выполнению второго запроса к БД внутри CursorAdapter, в основном это приведет к одному запросу в строке, и я боюсь, что это сильно повлияет на мою производительность (я все еще должен проверить его на реальном устройстве с существенной суммой Данных, чтобы увидеть, насколько это влияет).

Поэтому мой вопрос заключается в том, существуют ли какие-то стратегии, как избежать этого, учитывая мою модель данных или я должен в основном «жить» с этим 🙂

Вы жаловались на Twitter, что вы не получали никакой обратной связи. Я не очень удивлен, потому что, хотя ваш вопрос имеет примерный уровень детализации, он страдает двумя основными недостатками:

  1. Ваш вопрос, в конце, является неопределенным
  2. Ваш вопрос зависит от вашей собственной интерпретации того, что такое «это», к которому мы не привязаны

Следовательно, у меня нет четкой картины того, что вы считаете «странным». do...while() ? 🙂

Я собираюсь выйти на конечность и догадаться, что ваша забота – сделать второй запрос и объединить конкатенацию строк для каждой строки в ListView . Все зависит от того, считаете ли вы, что «список тегов с разделителями-запятыми» является частью модели данных или части презентации. Если это часть презентации, я не вижу, как вы можете избежать того, что вы здесь делаете.

Если вы действительно считаете, что это часть вашей модели данных, настройте ContentProvider чтобы предоставить список тегов с разделителями-запятыми как часть того, что вы запрашиваете в первую очередь (не показано).

В любом случае производительность является вероятной проблемой. Выполнение одного запроса в строке, особенно в момент прокрутки, вероятно, будет плохим. В конце концов, Ромен Гай многократно подчеркивает, что вам нужно перерабатывать строки в вашем адаптере, и я должен был бы предположить, что запрос базы данных является более дорогим, чем раздувание макета. К сожалению, вы пошли с моделью данных, которая подчеркивала пространство с течением времени, и поэтому вам придется заплатить пипец где-то вдоль линии.

Я протестировал свое решение (предложенное в моем вопросе) примерно с 100 записями. Он все еще использовался, но прокрутка была не такой гладкой, как можно было бы ожидать. Как уже говорилось в CommonsWare, лучше всего адаптировать модель данных или, по крайней мере, к ее агрегации, в конце концов, курсор содержит все данные, необходимые для отображения в пользовательском интерфейсе .

Я не хотел полностью менять базовый datamodel. Я сделал это, чтобы агрегировать данные таким образом, поскольку курсор, возвращаемый ContentProvider, содержит данные для устройств, включая уже подготовленную строку, обозначающую имена соответствующих ярлыков:

 | ID | NAME | ... | LABELSSTRING | ------------------------------------------------ | 1 | "My Device name" | ... | "Work, Friend" | | 1 | "Some other" | ... | | | 1 | "Yet another" | ... | "Work" | 

Это в значительной степени решает проблему, потому что нет необходимости требовать в bindView () для CursorAdapter для каждого устройства, что кстати. Довольно плохо. Это решение было возможно с помощью функции SQLite group_concat (X, Y) .

Intereting Posts