Статьи

Будьте ленивым, но продуктивным разработчиком Android, часть 5: Библиотека загрузки изображений

Добро пожаловать в пятую часть серии «Будьте ленивым, но продуктивным разработчиком Android». Если вы ленивый разработчик Android и ищете библиотеку загрузки изображений, которая могла бы помочь вам загружать изображения в асинхронном режиме без написания логики загрузки и кэширования изображений, тогда эта статья для вас.

Эта серия до сих пор:

  • Часть 1 : Мы посмотрели на RoboGuice, библиотеку внедрения зависимостей, с помощью которой мы можем уменьшить код базовой платы, сэкономить время и добиться повышения производительности при разработке приложений для Android.
  • Часть 2 : Мы видели и изучали Genymotion, который является эмулятором скорости ракеты и супер-быстрым эмулятором по сравнению с нативным эмулятором. И мы можем использовать Genymotion при разработке приложений и можем быстро тестировать приложения, что позволяет добиться производительности.
  • Часть 3 : Мы поняли и изучили библиотеки JSON Parsing (GSON и Jackson), с помощью которых мы можем повысить производительность приложений, уменьшить шаблонный код и тем самым оптимизировать производительность.
  • Часть 4. Мы поговорили об интерфейсе пользователя карты и изучили библиотеку карт, а также создали базовую карту и демонстрацию простого списка карт.

В этой части

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

Необходимые функции для загрузки изображений

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

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

Короче говоря, нам нужно написать код для управления всеми аспектами загрузки изображений, но есть несколько замечательных библиотек, с помощью которых мы можем загружать / загружать изображения асинхронно. Нам просто нужно вызвать метод загрузки изображения и обратные вызовы успеха / неудачи.

Асинхронная загрузка изображений

Рассмотрим случай, когда у нас есть 50 изображений и 50 заголовков, и мы пытаемся загрузить все изображения / текст в просмотр списка, он ничего не отобразит, пока все изображения не будут загружены.

Здесь асинхронный процесс загрузки изображения входит в картину. Асинхронная загрузка изображений — это не что иное, как процесс загрузки, который происходит в фоновом режиме, так что он не блокирует основной поток пользовательского интерфейса и позволяет пользователю играть с другими загруженными данными на экране. Изображения будут отображаться по мере загрузки из фоновых потоков.

Асинхронные библиотеки загрузки изображений

  1. Универсальный загрузчик изображений Nostra —  https://github.com/nostra13/Android-Universal-Image-Loader
  2. Пикассо —  http://square.github.io/picasso/
  3. UrlImageViewHelper  от Koush
  4. Залп  — от членов команды Android @ Google
  5. Загрузчик изображений Novoda —  https://github.com/novoda/ImageLoader

Давайте рассмотрим примеры использования библиотек Picasso и Universal Image loader.

Пример 1: Универсальный загрузчик изображений Nostra

Загрузка изображения с помощью UniversalImageLoader

Шаг 1: Инициализация конфигурации ImageLoader

?
public class MyApplication extends Application{
@Override
public void onCreate() {
// TODO Auto-generated method stub
super.onCreate();
// Create global configuration and initialize ImageLoader with this configuration
ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(getApplicationContext()).build();
ImageLoader.getInstance().init(config);
}
}

Шаг 2. Объявление класса приложения внутри тега приложения в файле AndroidManifest.xml

?
<application android:name="MyApplication">

Шаг 3: Загрузите изображение и отобразите в ImageView

?
ImageLoader.getInstance().displayImage(objVideo.getThumb(), holder.imgVideo);

Теперь Universal Image loader также предоставляет функциональность для реализации обратного вызова «успех / сбой», чтобы проверить, была ли загрузка изображения неудачной или успешной.

?
ImageLoader.getInstance().displayImage(photoUrl, imgView,
new ImageLoadingListener() {
@Override
public void onLoadingStarted(String arg0, View arg1) {
// TODO Auto-generated method stub
findViewById(R.id.EL3002).setVisibility(View.VISIBLE);
}
@Override
public void onLoadingFailed(String arg0, View arg1,
FailReason arg2) {
// TODO Auto-generated method stub
findViewById(R.id.EL3002).setVisibility(View.GONE);
}
@Override
public void onLoadingComplete(String arg0, View arg1,
Bitmap arg2) {
// TODO Auto-generated method stub
findViewById(R.id.EL3002).setVisibility(View.GONE);
}
@Override
public void onLoadingCancelled(String arg0, View arg1) {
// TODO Auto-generated method stub
findViewById(R.id.EL3002).setVisibility(View.GONE);
}
});

Пример 2: Пикассо

Прямая загрузка изображения:

?
Picasso.with(context).load("http://postimg.org/image/wjidfl5pd/").into(imageView);

Изменение размера изображения:

?
Picasso.with(context)
.load(imageUrl)
.resize(100, 100)
.centerCrop()
.into(imageView)

Пример 3: библиотека UrlImageViewHelper

UrlImageViewHelper от Koush

Это библиотека Android, которая устанавливает содержимое ImageView из URL-адреса, управляет загрузкой изображений, кэшированием, а также готовит кофе.

UrlImageViewHelper автоматически загружает и управляет всеми веб-изображениями и изображениями. Дубликаты URL не будут загружены в память дважды. Память растрового изображения управляется с помощью хеш-таблицы со слабой ссылкой, поэтому, как только изображение больше не используется вами, оно будет автоматически собирать мусор.

Прямая загрузка изображения:

?
UrlImageViewHelper.setUrlDrawable(imgView, "http://yourwebsite.com/image.png");

Заполнитель изображения при загрузке изображения:

?
UrlImageViewHelper.setUrlDrawable(imgView, "http://yourwebsite.com/image.png", R.drawable.loadingPlaceHolder);

Кэшируйте изображения только на минуту:

?
UrlImageViewHelper.setUrlDrawable(imgView, "http://yourwebsite.com/image.png", null, 60000);

Пример 4: залповая библиотека

Yes Volley is a library developed and being managed by some android team members at Google, it was announced by Ficus Kirkpatrick during the last I/O. I wrote an article about Volley library 10 months back :) , read it and give it a try if you haven’t used it yet.

Let’s look at an example of image loading using Volley.

Step 1: Take a NetworkImageView inside your xml layout.

?
<com.android.volley.toolbox.NetworkImageView
android:id="@+id/imgDemo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:scaleType="centerCrop"/>

Step 2: Define a ImageCache class

Yes you are reading title perfectly, we have to define an ImageCache class for initializing ImageLoader object.

?
public class BitmapLruCache
extends LruCache<String, Bitmap>
implements ImageLoader.ImageCache {
public BitmapLruCache() {
this(getDefaultLruCacheSize());
}
public BitmapLruCache(int sizeInKiloBytes) {
super(sizeInKiloBytes);
}
@Override
protected int sizeOf(String key, Bitmap value) {
return value.getRowBytes() * value.getHeight() / 1024;
}
@Override
public Bitmap getBitmap(String url) {
return get(url);
}
@Override
public void putBitmap(String url, Bitmap bitmap) {
put(url, bitmap);
}
public static int getDefaultLruCacheSize() {
final int maxMemory =
(int) (Runtime.getRuntime().maxMemory() / 1024);
final int cacheSize = maxMemory / 8;
return cacheSize;
}
}

Step 3: Create an ImageLoader object and load image
Create an ImageLoader object and initialize it with ImageCache object and RequestQueue object.

?
ImageLoader.ImageCache imageCache = new BitmapLruCache();
ImageLoader imageLoader = new ImageLoader(Volley.newRequestQueue(context), imageCache);

Step 4: Load an image into ImageView

?
NetworkImageView imgAvatar = (NetworkImageView) findViewById(R.id.imgDemo);
imageView.setImageUrl(url, imageLoader);

Which library to use?

Can you decide which library you would use? Let us know which and what are the reasons? :)

Selection of the library is always depends on the requirement. Let’s look at the few fact points about each library so that you would able to compare exactly and can take decision.

Picasso:

  • It’s just a one liner code to load image using Picasso.
  • No need to initialize ImageLoader and to prepare a singleton instance of image loader.
  • Picasso allows you to specify exact target image size. It’s useful when you have memory pressure or performance issues, you can trade off some image quality for speed.
  • Picasso doesn’t provide a way to prepare and store thumbnails of local images.
  • Sometimes you need to check image loading process is in which state, loading, finished execution, failed or cancelled image loading. Surprisingly It doesn’t provide a callback functionality to check any state. “fetch()” dose not pass back anything. “get()” is for synchronously read, and “load()” is for asynchronously draw a view.

Universal Image loader (UIL):

  • It’s the most popular image loading library out there. Actually, it’s based on the Fedor Vlasov’s project
  • which was again probably a very first complete solution and also a most voted answer (for the image loading solution) on Stackoverflow.

  • UIL library is better in documentation and even there’s a demo example which highlights almost all the features.
  • UIL provides an easy way to download image.
  • UIL uses builders for customization. Almost everything can be configured.
  • UIL doesn’t not provide a way to specify image size directly you want to load into a view. It uses some rules based on the size of the view. Indirectly you can do it by mentioning ImageSize argument in the source code and bypass the view size checking. It’s not as flexible as Picasso.

Volley:

  • It’s officially by Android dev team, Google but still it’s not documented.
  • It’s just not an image loading library only but an asynchronous networking library
  • Developer has to define ImageCache class their self and has to initialize ImageLoader object with RequestQueue and ImageCache objects.

So now I am sure now you can be able to compare libraries. Choosing library is a bit difficult talk because it always depends on the requirement and type of projects. If the project is large then you should go for Picasso or Universal Image loader. If the project is small then you can consider to use Volley librar, because Volley isn’t an image loading library only but it tries to solve a more generic solution.).

I suggest you to start with Picasso. If you want more control and customization, go for UIL.

Read more:

  1. http://blog.bignerdranch.com/3177-solving-the-android-image-loading-problem-volley-vs-picasso/
  2. http://stackoverflow.com/questions/19995007/local-image-caching-solution-for-android-square-picasso-vs-universal-image-load
  3. https://plus.google.com/103583939320326217147/posts/bfAFC5YZ3mq

Hope you liked this part of “Lazy android developer: Be productive” series. Till the next part, keep exploring image loading libraries mentioned above and enjoy!