Поток пользовательского интерфейса — плохое место для длительных операций, таких как загрузка данных. Вы никогда не знаете, сколько времени займет загрузка данных, особенно если эти данные получены от поставщика контента или из сети. Android 3.0 (Honeycomb) представил концепцию Loaders и, в частности, класс CursorLoader, который снимает с себя нагрузку по загрузке данных в потоке и сохраняет их постоянными во время кратковременных событий обновления активности, таких как изменение ориентации. Мы включим Loader в качестве новой функции в нашу текущую серию учебных пособий, создавая приложение для чтения учебных пособий, которое пока не названо.
Если вы уделяли пристальное внимание нашему последнему учебнику « Основы Android: работа с поставщиками контента» , вы, возможно, заметили, что мы воспользовались сокращением. Мы использовали метод managedQuery () класса Activity, который является устаревшим методом. Этот метод представляет собой «старый» способ позволить деятельности управлять курсором. Теперь мы переключим его на новый способ, используя CursorLoader, как предложено в последней документации SDK. Мы можем сделать это безопасно, потому что хотя класс CursorLoader был включен в Android 3.0, он также является частью новой библиотеки совместимости, которую мы обсуждали в разделе Совместимость Android: работа с фрагментами , и, следовательно, может использоваться на устройствах начиная с Android 1.6.
Шаг 0: Начало работы
В этом руководстве предполагается, что вы начнете с того момента, когда наше руководство под названием « Основы Android: работа с поставщиками контента» было прекращено. Вы можете скачать этот код и работать оттуда, хотя у вас будут некоторые задачи, которые вам придется выполнять без посторонней помощи, или вы можете просто скачать код для этого урока и следовать ему. Выбор ваш.
Шаг 1. Использование правильных версий классов
Обычно мы можем избежать неприятностей, просто используя оператор импорта по умолчанию, который дает нам Eclipse. Однако, чтобы загрузчики работали, мы должны убедиться, что мы используем правильные версии классов. Вот соответствующие заявления на импорт:
1
2
3
4
5
6
|
import android.support.v4.app.ListFragment;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;
import android.support.v4.widget.CursorAdapter;
import android.support.v4.widget.SimpleCursorAdapter;
|
Этот импорт заменяет существующие операторы импорта CursorAdapter, найденные в классе TutListFragmet предыдущего руководства. Это единственный класс, который нам нужно изменить. Обычно мы не говорим об операторах импорта, но при создании этого примера Eclipse продолжал ссылаться на неправильный пакет CursorLoader, и нам пришлось вносить изменения вручную, поэтому мы вызываем его здесь на нашем первом шаге.
Шаг 2: Реализация обратных вызовов
Затем измените класс TutListFragment, чтобы он теперь реализовывал LoaderManager.LoaderCallbacks. Полученный класс TutListFragment теперь будет иметь три новых метода для переопределения:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
|
public class TutListFragment extends ListFragment implements
LoaderManager.LoaderCallbacks<Cursor> {
// … existing code
// LoaderManager.LoaderCallbacks<Cursor> methods:
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
// TBD
}
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
// TBD
}
@Override
public void onLoaderReset(Loader<Cursor> loader) {
// TBD
}
}
|
Шаг 3: Инициализация загрузчика
Вам необходимо внести несколько изменений в метод onCreate () класса TutListFragment. Во-первых, курсор больше не будет создаваться здесь. Во-вторых, загрузчик должен быть инициализирован. И в-третьих, поскольку курсор больше не доступен сразу (поскольку он будет загружен в отдельном потоке), инициализация адаптера должна быть изменена. Изменения в методе onCreate () заключены здесь:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
|
// TutListFragment class member variables
private static final int TUTORIAL_LIST_LOADER = 0x01;
private SimpleCursorAdapter adapter;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
String[] uiBindFrom = { TutListDatabase.COL_TITLE };
int[] uiBindTo = { R.id.title };
getLoaderManager().initLoader(TUTORIAL_LIST_LOADER, null, this);
adapter = new SimpleCursorAdapter(
getActivity().getApplicationContext(), R.layout.list_item,
null, uiBindFrom, uiBindTo,
CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);
setListAdapter(adapter);
}
|
Как видите, мы внесли три изменения. Объект Cursor и результирующий вызов query () были удалены. Вместо этого мы вызываем метод initLoader () класса LoaderManager. Хотя этот метод возвращает объект загрузчика, нам не нужно его хранить. Вместо этого LoaderManager заботится о деталях для нас. Все загрузчики уникально идентифицированы, поэтому система знает, должен ли он быть заново создан или нет. Мы используем константу TUTORIAL_LIST_LOADER, чтобы идентифицировать единственный загрузчик, который сейчас используется. Наконец, мы изменили адаптер на переменную-член класса, и ему пока не передается курсор, используя нулевое значение.
Шаг 4: Создание загрузчика
Загрузчик не создается автоматически. Это работа для класса LoaderManager.LoaderCallbacks. CursorLoader, который нам нужно создать и вернуть из метода onCreateLoader (), принимает параметры, аналогичные методу managedQuery (), который мы использовали ранее. Вот полная реализация метода onCreateLoader ():
1
2
3
4
5
6
7
8
|
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
String[] projection = { TutListDatabase.ID, TutListDatabase.COL_TITLE };
CursorLoader cursorLoader = new CursorLoader(getActivity(),
TutListProvider.CONTENT_URI, projection, null, null, null);
return cursorLoader;
}
|
Как видите, это довольно просто и действительно похоже на вызов managedQuery (), но вместо Cursor мы получаем CursorLoader. И если говорить о курсорах …
Шаг 5: Использование курсора
Вам может быть интересно, что случилось с объектом Cursor? Когда система заканчивает извлечение курсора, происходит вызов метода onLoadFinished (). Обработка этого метода обратного вызова довольно проста:
1
2
3
4
|
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
adapter.swapCursor(cursor);
}
|
Новый метод swapCursor (), представленный в API Level 11 и предоставленный в пакете совместимости, назначает новый курсор, но не закрывает предыдущий. Это позволяет системе отслеживать курсора и управлять им для нас, оптимизируя при необходимости.
Шаг 6: Реализация сброса обратного вызова
Последний метод обратного вызова для реализации — метод onLoaderReset (). Этот метод запускается, когда загрузчик сбрасывается, и данные загрузчика больше не доступны. Наше единственное использование — внутри адаптера, поэтому мы просто очистим курсор, который мы использовали, с другим вызовом метода swapCursor ():
1
2
3
4
|
@Override
public void onLoaderReset(Loader<Cursor> loader) {
adapter.swapCursor(null);
}
|
Шаг 7: Тестирование результатов
На этом этапе вы завершили перевод TutListFragment в реализацию на основе загрузчика. Запустив приложение сейчас, вы, вероятно, заметите, что оно в основном ведет себя одинаково. Итак, как вы узнаете, что это изменение что-то делает? Мы оставляем эту задачу в качестве упражнения для читателя. Как бы вы проверили эффективность этого решения?
СОВЕТ: Этого можно достичь с помощью одной функциональной строки кода, для которой потребуется блок try-catch.
Вывод
Переместив загрузку данных из основного потока пользовательского интерфейса приложения в CursorLoader, вы повысили скорость реакции приложения, особенно во время изменения ориентации. Если бы контент-провайдеру потребовалось 10 секунд на запрос, пользовательский интерфейс не был бы затронут отрицательно, тогда как в его предыдущей реализации он, вероятно, вызвал бы появление страшного диалогового окна «Принудительное закрытие».
Об авторах
Разработчики мобильных приложений Лорен Дарси и Шейн Кондер являются соавторами нескольких книг по разработке Android: углубленная книга по программированию под названием « Разработка беспроводных приложений для Android» и « Самс научи себя разрабатывать приложения для Android за 24 часа» . Когда они не пишут, они тратят свое время на разработку мобильного программного обеспечения в своей компании и оказание консультационных услуг. С ними можно связаться по электронной почте [email protected] , через их блог на androidbook.blogspot.com и в Twitter @androidwireless .