Load ảnh trong Android với Universal Image Loader

1. Giới thiệu

Universal Image Loader là một thư viện mã nguồn mở, mục đích xây dựng là để cung cấp một công cụ mạnh mẽ, linh hoạt và có tính tùy biến cao cho việc load, cache và hiển thị ảnh. Nó cung cấp rất nhiều những tùy chọn cấu hình và có khả năng control tốt trong quá trình tải và cache ảnh.

Hiện tại, Universal Image Loader ngưng đc phát triển thêm từ tháng 11/2015 do tác giả k có thời gian. Tuy nhiên, là 1 thư viện mã nguồn mở, bạn hoàn toàn có thể fork project và tự phát triển thêm cho riêng mình hoặc cho cộng đồng android developer.

2. Các tính năng

  • Load ảnh đa luồng (đồng bộ và bất đồng bộ)
  • Khả năng tùy biến cao (các tùy chọn cho viện thực thi đa luồng, tải ảnh, giải mã, cache bộ nhớ, hiển thị v.v.v.).
  • Cache ảnh trong bộ nhớ hoặc/và trên ổ đĩa
  • Theo dõi quá trình load ảnh (bao gồm quá trình download ảnh)

3. Tải xuống

universal-image-loader-1.9.5.jar

Github repo : https://github.com/nostra13/Android-Universal-Image-Loader

4. Hướng dẫn sử dụng

Một số mẫu URI có thể sử dụng:

"http://site.com/image.png" // từ trên mạng
"file:///mnt/sdcard/image.png" // từ SD card
"file:///mnt/sdcard/video.mp4" // từ SD card (video thumbnail)
"content://media/external/images/media/13" // từ content provider
"content://media/external/video/media/13" // từ content provider (video thumbnail)
"assets://image.png" // từ assets
"drawable://" + R.drawable.img // từ drawables (không bao gồm ảnh 9patch)

CHÚ Ý Sử dụng "drawable://" chỉ khi thực sự cần nó. Luôn cân nhắc sử dụng ImageView.setImageResource(...) thay vì sử dụng cho việc load drawable

Khởi tạo đối tượng

ImageLoader imageLoader = ImageLoader.getInstance();
imageLoader.init(ImageLoaderConfiguration.createDefault(context));

Ở trên ta đã khởi tạo đối tượng ImageLoader vói cấu hình tùy chọn mặc định. Bạn có thể thay đổi những tùy chọn cho riêng mình giống như ví dụ ở phần 5

Load ảnh, giải mã nó thành bitmap và hiển thị bitmap lên ImageView (hay bất cứ lớp view nào implement interface ImageAware

imageLoader.displayImage(imageUri, imageView);

Bạn cũng có thể load ảnh, giải mã nó thành bitmap và thực hiện bất cứ điều gì bạn muốn ở từng sự kiện tuơng ứng trong quá trình xử lý nó, hay theo dõi quá trình load ảnh như dưới đây.

// Load image, decode it to Bitmap and display Bitmap in ImageView (or any other view
//  which implements ImageAware interface)

imageLoader.displayImage(imageUri, imageView, options, new ImageLoadingListener() {
    @Override
    public void onLoadingStarted(String imageUri, View view) {
        ...
    }
    @Override
    public void onLoadingFailed(String imageUri, View view, FailReason failReason) {
        ...
    }
    @Override
    public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
        ...
    }
    @Override
    public void onLoadingCancelled(String imageUri, View view) {
        ...
    }
}, new ImageLoadingProgressListener() {
    @Override
    public void onProgressUpdate(String imageUri, View view, int current, int total) {
        ...
    }
});

Hoặc đơn giản hơn, ta có thể sử dụng SimpleImageLoadingListener thay vì ImageLoadingListener nếu như không muốn bị buộc phải cài đè 4 phuơng thức trên (cài đề nếu bạn muốn)

imageLoader.loadImage(url, new SimpleImageLoadingListener(){
            @Override
            public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
                Toast.makeText(mContext, "Đã load xong", Toast.LENGTH_SHORT).show();
                imageView.setImageBitmap(loadedImage);
            }
        });

Bạn cũng có thể load ảnh, giải mã ảnh để nhận về bitmap 1 cách đồng bộ bằng cách sử dụng hàm loadImageSync(Uri uri)

Bitmap bmp = imageLoader.loadImageSync(imageUri);

Bạn cũng có thể thêm tùy chọn về kích cỡ của ảnh nếu muốn như sau

// Load image, decode it to Bitmap and return Bitmap to callback
ImageSize targetSize = new ImageSize(80, 50); // result Bitmap will be fit to this size
imageLoader.loadImage(imageUri, targetSize, options, new SimpleImageLoadingListener() {
    @Override
    public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
        // Do whatever you want with Bitmap
    }
});

Hoặc dùng cách dưới đây mà không thiết kế bất cứ gì cho từ ảnh

// Load image, decode it to Bitmap and return Bitmap synchronously
ImageSize targetSize = new ImageSize(80, 50); // result Bitmap will be fit to this size
Bitmap bmp = imageLoader.loadImageSync(imageUri, targetSize, options);

5. Luồng xử lý

UIL_Flow.png

Luồng xử lý đc thể hiện rất rõ trên hình nên mình sẽ không mô tả chỉ tiết. Nhưng ta có thể thấy nó trải qua 7 giai đoạn đối với một ảnh mới hoàn toàn bao gồm

  • Tải ảnh
  • Cache ảnh lên đĩa nhớ
  • Giải mã ảnh thành bitmap
  • Tiền xử lý bitmap
  • Lưu bitmap đã được xử lý vào bộ nhớ
  • Hậu xử lý
  • Hiển thị ảnh

Đối với ảnh không mới (đã được luư trên bộ nhớ hoặc đĩa nhớ), một số giai đoạn đầu sẽ bị lược bỏ (do thực tế đã được thực hiện trứoc đó) như hình phía trên.

6. Ví dụ

Dưới đây là 1 ví dụ cho việc sử dụng Universal Image Loader

import android.app.Application;
import com.nostra13.universalimageloader.cache.memory.impl.WeakMemoryCache;
import com.nostra13.universalimageloader.core.DisplayImageOptions;
import com.nostra13.universalimageloader.core.ImageLoader;
import com.nostra13.universalimageloader.core.ImageLoaderConfiguration;
import com.nostra13.universalimageloader.core.assist.ImageScaleType;
import com.nostra13.universalimageloader.core.display.FadeInBitmapDisplayer;

public class MyApplication extends Application {
	@Override
	public void onCreate() {
		super.onCreate();

        String url = "http://img.blogtamsu.vn/2015/11/ngoc-trinh-blogtamsuvn-38.jpg";
		// Cấu hình tùy chọn hiển thị ảnh
		DisplayImageOptions defaultOptions = new DisplayImageOptions.Builder()
				.cacheOnDisc(true).cacheInMemory(true)
				.imageScaleType(ImageScaleType.EXACTLY)
				.displayer(new FadeInBitmapDisplayer(300)).build();

		ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(
				getApplicationContext())
				.defaultDisplayImageOptions(defaultOptions)
				.memoryCache(new WeakMemoryCache())
				.discCacheSize(100 * 1024 * 1024).build();

		// Khởi tại đối tượng imageLoader với cấu hình ta đã set vên trên
        // bạn cũng có thể sử dụng config mặc định bằng cách
        // imageLoader.init(ImageLoaderConfiguration.createDefault(mContext));
		ImageLoader imageLoader = ImageLoader.getInstance().init(config);
		ImageView imageView = (ImageView) findViewById(R.id.imageView1)

		//download ảnh và show ImageView tại đây
		imageLoader.displayImage(url, imageView, options);

	}
}

Còn do dự gì nữa? Hãy tạo một project và thử ngay Universal Image Loader để hiểu hơn về cách nó hoạt động. Chúc các bạn vui vẻ.