#android #android-adapter #android-loadermanager
#Android #android-адаптер #android-loadermanager
Вопрос:
Я создаю новое приложение для Android, которое, по сути, отражает данные, доступные на нашем веб-сайте. Графический интерфейс будет отображать либо a ListView
с изображениями и текстом в каждом элементе, либо a RelativeLayout
, который будет отображать сведения об одном элементе.
Чтобы повысить скорость реагирования в этом приложении, я хотел бы прочитать данные из внутренней базы данных, если данные достаточно свежие, и прочитать данные из серверного API (JSON через http), если внутренние данные слишком старые (и затем заполнить внутреннюю базу данных новыми данными).
Из основных руководств кажется, что при чтении из внутренней базы данных следует использовать DB и SimpleCursorAdapter
(*). Но при чтении из Интернета, я думаю, я бы использовал ArrayList
и ArrayAdapter
.
Существует ли какой-либо тип адаптера, который может обрабатывать обе ситуации?
(*) Я знаю, что последнее решение — использовать LoaderManager с CursorLoader, но я пытаюсь поддерживать Android 2.1. Я полагаю, что могу поместить SimpleCursorAdapter в AsyncTask и избежать ANR.
Комментарии:
1. Почему бы вам не обновить свою базу данных, если данные слишком старые, и новые данные доступны в Интернете, а затем использовать их с помощью курсора?
2. Я хочу отображать данные непосредственно из Интернета, а затем обновлять базу данных в фоновом режиме.
3. Вместо отображения данных непосредственно из Интернета я рекомендовал вам сначала обновить базу данных, а затем просто отобразить эти данные с помощью курсора, чтобы вы могли избежать использования arraylist, а также повторного анализа данных для отображения и хранения в базе данных.
4. Учитывая тесты, которые я провел до сих пор с SQLite, я почти уверен, что это значительно сократит время отклика, так что на данный момент это не вариант.
Ответ №1:
Конечно, вы можете использовать SimpleCursorAdapter
и AsyncTask
. Но с помощью пакета совместимости с Android вы можете начать использовать CursorLoader
API с Android 1.6. Загрузчик API упрощает управление жизненным циклом Cursors
.
Я бы предложил использовать CursorLoader
API для извлечения Cursor
из ContentProvider
или базы данных. И использовать AsyncTask
(или пользовательскую реализацию AsyncLoader) для извлечения данных с сервера и обновления ContentProvider
.
Если вы используете два разных AsyncTasks
(или Loaders
) для каждой задачи (загрузка курсора и обновление данных), вы можете сделать свое ListView
обновление автоматически, если данные в базе данных изменились.
Для этого установите уведомление Uri
для Cursor
файла, который вы извлекли из базы данных:
cursor.setNotificationUri(getContentResplver(), Uri.parseString("mydata://someuri"));
И если вы обновили данные, отправьте уведомление об этом Uri
:
getContentResolver().notifyChange(Uri.parseString("mydata://someuri"), null);
Комментарии:
1. Спасибо за этот ответ; это, вероятно, лучшее долгосрочное решение, но для целей крайнего срока я пока внедряю что-то вроде другого ответа.
Ответ №2:
Я думаю, вы можете написать пользовательский адаптер, расширяющий класс BaseAdapter, и использовать его для обоих случаев.
В вашем классе, который расширяет BaseAdapter, у вас будет List<DataEntry>
, где DataEntry — это класс Java POJO, представляющий данные, поступающие из Web или db (при условии, что они имеют те же свойства). Предполагая, что вы заполнили List<DataEntry>
объектами DataEntry, уже содержащими данные, вы можете сделать следующее:
1) В методе getView() класса, который расширяет BaseAdapter, в inflate вы будете использовать XML-макет, который в основном представляет 1 строку данных. Предполагая, что вы будете отображать данные через TextView, макет из 1 строки данных будет содержать столько элементов TextView, сколько полей данных вашего объекта DataEntry. После раздувания вы помещаете значения в текстовые представления, такие как:
TextView someTextViewToDisplayField = (TextView) convertView.findViewById(R.id.yourID);
someTextViewToDisplayField.setText(String.valueOf(dataEntry.getWhateverProperty()));
2) в процессе обновления пользовательского интерфейса в вашем макете у вас должен быть ListView типа:
<ListView android:id="@ id/YourListViewID" android:layout_width="fill_parent"
android:layout_height="wrap_content"></ListView>
и после этого вы инициализируете свой класс, который расширяет BaseAdapter
ListView listView = (ListView) findViewById(R.id.YourListViewID);
YourClassExtendingBaseAdapter adapter =
new YourClassExtendingBaseAdapter(this, listOfEntryDataObjects);
listView.setAdapter(adapter);
listOfEntryDataObjects List<DataEntry>
уже заполнен данными. ‘This’ в конструкторе — это контекст, связанный с текущим действием, из которого вы выполняете вызов.
Структура класса, расширяющего BaseAdapter:
public class YourClassExtendingBaseAdapter extends BaseAdapter {
private Context context;
private List<DataEntry> entries;
public YourClassExtendingBaseAdapter(Context context,
List<DataEntry> entries) {
this.context = context;
this.entries = entries;
}
// Overwriting necessary methods
}
Комментарии:
1. Мне нравится ваша идея, но меня немного беспокоит моя способность расширить BaseAdapter таким образом, чтобы включить функциональность как DBCursor, так и ArrayAdapter ….
2. Я предполагаю, что данные, поступающие из базы данных и Интернета, могут быть обернуты в объект «DataEntry». После этого вы используете только свой адаптер для отображения данных.
3. хорошо, я собираюсь поискать несколько руководств по расширению BaseAdapter и выбрать ваш ответ, если я смогу заставить его работать … спасибо за ваш ответ!
4. Добро пожаловать, это приложение, которое я использовал некоторое время назад, чтобы начать: code.google.com/p/myandroidwidgets/source/browse/trunk /…