Розробка клієнта для галереї LiveStreet

Наша студія вже давно розробляє плагіни для популярної CMS LiveStreet, одним із яких є зручна та проста у використанні галерея. У рамках розвитку нових напрямків, як одне з перших додатків, студією був розроблений клієнт для цього популярного плагіна.
Задача полягала в тому, щоб розробити клієнт-додаток, який дозволить користувачеві переглядати всі графічні файли на його пристрої, за бажанням сфотографувати новий, відзначити їх для додавання в галерею та відправити на сервер.
Основною проблемою був вивід зображень користувача у вигляді скролюючого альбому. З допомогою MediaStore.Images
ми отримали мініатюри всіх зображень, які є на пристрої, і це не виявилося великою проблемою. Але коли ми намагалися використовувати GridView
зі стандартним адаптером, то зіткнулися з тим, що прокрутка сильно «тормозила». Як виявилося, затримки проявляються при підгрузці мініатюр в головному потоці. Ми пробували тягнути прев'ю в AsyncTask
, що частково допомогло. Але прокрутка все одно йшла ривками.
Маючи досвід підгрузки картинок в ListView
з сервера, ми вирішили піти тим же шляхом, використовуючи бібліотеку Universal Image Loader
.
Після підключення бібліотеки в класі, успадкованому від Application
, налаштовуємо ImageLoader
. Після проведення кількох тестів було вирішено використовувати стандартні налаштування:
ImageLoader.getInstance().init(ImageLoaderConfiguration.createDefault(getApplicationContext()));
Далі налаштовуємо опції відображення:
public static DisplayImageOptions options = new DisplayImageOptions.Builder() .showStubImage(R.drawable.empy_photo) .resetViewBeforeLoading() .cacheInMemory() .cacheOnDisc() .imageScaleType(ImageScaleType.IN_SAMPLE_POWER_OF_2) .build();
Опишу детальніше:
showStubImage(R.drawable.empy_photo)
— зображення, яке буде відображатися до завантаження або в разі невдалої загрузки.resetViewBeforeLoading()
— обнуляти вьюху перед завантаженням нового зображення.cacheInMemory()
— кешування в оперативній пам'яті.cacheOnDisc()
— кешування у внутрішній пам'яті.imageScaleType(ImageScaleType.IN_SAMPLE_POWER_OF_2)
— декодувати зображення максимально швидко (ImageScaleType.POWER_OF_2
) або максимально економно для оперативної пам'яті (ImageScaleType.EXACT
).
Тепер можна використовувати ImageLoader
в адаптері:
ImageLoader.getInstance().displayImage(item.thumbUri.toString(), holder.imageview, LsGalleryApp.options);
Після цього проблема з прокруткою ривками була вирішена, але з'явилася нова — тумбики після прокрутки занадто довго завантажувалися. Як виявилося, все діло в отриманні id зображень з MediaStore
. Найвдаліший спосіб вирішення — отримати всі id під час завантаження програми. Для цього був написаний невеличкий AsyncTask
:
private class GetImageTask extends AsyncTask{ String message; ProgressDialog dialog; public GetImageTask(String message) { this.message = message; this.dialog = new ProgressDialog(context); } @Override protected Void doInBackground(Void... params) { externalContentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI; String[] projection = {}; String selection = ""; String[] selectionArgs = null; externalCursor = getContentResolver().query(externalContentUri , projection, selection, selectionArgs, null); externalColumnIndex = externalCursor.getColumnIndex(MediaStore.Images.Media._ID); imageAdapter = new ImageAdapter(context, callback_click_image); imageAdapter.initialized(); return null; } @Override protected void onPreExecute() { dialog.setMessage(message); dialog.setIndeterminate(true); dialog.setCancelable(false); dialog.show(); } @Override protected void onPostExecute(Void result) { SetGridView(); if (dialog.isShowing()) dialog.dismiss(); } }
Для отримання прев'юшки в адаптері використовуємо таку функцію:
protected Uri getThumbUri(Uri original) { String uri = ""; Cursor cursor = MediaStore.Images.Thumbnails.queryMiniThumbnail( mContext.getContentResolver(), Long.valueOf(original.getLastPathSegment()), MediaStore.Images.Thumbnails.MINI_KIND, null); if (cursor != null && cursor.getCount() > 0) { cursor.moveToFirst(); uri = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Thumbnails._ID)); cursor.close(); Uri thumb = Uri.withAppendedPath(MediaStore.Images.Thumbnails.EXTERNAL_CONTENT_URI, uri); return thumb; } else return null; }
В результаті за допомогою Universal Image Loader
ми маємо чудово оптимізовану галерею, яка використовує AsyncTask
для підвантаження мініатюр і має свій кеш. Додаток інтуїтивно зрозуміле у використанні. Сподіваємося, що воно буде корисним для вас.