View
4.048
Download
4
Category
Preview:
DESCRIPTION
Citation preview
Клиент-серверное взаимодействие под Android
в деталях
Кирилл Зотин
Android dev lead
23.04.2011
Введение
• Преимущества родных приложений над мобильными версиями сайтов
• Специфика мобильных приложений:
Document-ориентированая модель
VS
Database-ориентированная модель
Преимущества над мобильными версиями сайтов.
• Тесная интеграция с платформой
• Улучшение поведения платформы
• Фоновая работа
• Более высокая скорость работы
• "родной" пользовательский интерфейс
Document-ориентированаямодель данных
Database-ориентированная модель данных
Типичная реализация
О проблеме
• OS в любой момент может остановить процесс
• Данные не всегда сохранены
Правильная реализация1:Service API
Правильная реализация2:Content Provider API
Network-MVC
Правильная реализация3:Content Provider + SyncAdapter
Tips & Tricks
• Выполняйте запросы к БД не в UI потоке
• Используйте транзакции
• Делайте код хорошо читаемым
• Используйте Gzip сжатие
• Android 3.0: Loaders
• Удобный класс IntentService
Выполняйте запросы к БД не в UI потоке
• Используйте (Notifying)AsyncQueryHandler
public class YourActivity extends Activity implements AsyncQueryListener {
@Override
public void onQueryComplete(int token, Object cookie,
final Cursor cursor) {
startManagingCursor(cursor);
. . .
}
}
Используйте транзакции
@Override
public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations)
throws OperationApplicationException {
final SQLiteDatabase db = mDatabaseHelper.getWritableDatabase();
db.beginTransaction();
try {
final int numOperations = operations.size();
final ContentProviderResult[] results = new ContentProviderResult[numOperations];
for (int i = 0; i < numOperations; i++) {
results[i] = operations.get(i).apply(this, results, i);
}
db.setTransactionSuccessful();
return results;
} finally {
db.endTransaction();
}
Группируйте детали запросов в одном месте
ПлохоCursor mCursor = query(true,
DATABASE_TABLE_EMAIL,
new String[] {
KEY_ROWID, KEY_EMAIL_NAME
},
KEY_ROWID + "=" + rowId,
null, null, null, null, null);
if (mCursor.moveToFirst()) {
long id = mCursor.getLong(
mCursor.getColumnIndexOrThrow(KEY_ROWID));
String name = mCursor.getString(
mCursor.getColumnIndexOrThrow(KEY_EMAIL_NAME));
}
Хорошоinterface ReviewsQuery {
final String[] PROJECTION = new String[] {Reviews._ID,Reviews.TITLE,Reviews.SUBTITLE,Reviews.IMG_URL_SMALL,Reviews.ARTICLE_ID
};int ID = 0;int TITLE = 1;int SUBTITLE = 2;int IMG_URL = 3;int ARTICLE_ID = 4;
String DEFAULT_SORT = Reviews.DATE + " desc";}...startAsyncQuery(QUERY_REVIEWS_ITEMS, null,
Reviews.CONTENT_URI,ReviewsQuery.PROJECTION,selection, null,ReviewsQuery.DEFAULT_SORT);
…final String url =
getCursor().getString(ReviewsQuery.IMG_URL);
Используйте сжатие Gzip
HttpGet request = new HttpGet(uri);
request.addHeader("Accept-Encoding", "gzip");
HttpResponse response = getHttpClient().execute(request);
Header contentEncoding = response.getFirstHeader("Content-Encoding");
if (contentEncoding != null &&
contentEncoding.getValue().equalsIgnoreCase("gzip")) {
is = new GZIPInputStream(is);
}
Honeycomb API: CursorLoader
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
getLoaderManager().initLoader(0, null, this);
}
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
final String eventId = getArguments().getString(EXTRA_EVENT_ID);
return new CursorLoader(getActivity(),
Events.CONTENT_URI,
EventQuery.PROJECTION,
EventQuery.SELECTION, new String[] {eventId}, null);
}
Использование IntentService
• Для обработки Intent стартует Service
• Запрос обрабатывается в отдельном потоке
• Параллельные запросы кладутся в одну очередь.
Выводы
• Не обрабатывайте сетевые операции в Activity, используйте Service
• Сохраняйте данные часто
• Все запросы к БД – в отдельный поток
• Минимизируйте трафик сетевых операций
• Используйте локальный кэш данных
Recommended