Universal-Image-Loader系列1-配置使用

Android-Universal-Image-Loader

官方使用介紹,參考
wiki

默認值

ImageLoaderConfiguration

全局顯示選項

/* ImageLoader Configuration (ImageLoaderConfiguration) is global for application. You should set it once.
All options in Configuration builder are optional. Use only those you really want to customize.
See default values for config options in Java docs for every option.*/
// DON'T COPY THIS CODE TO YOUR PROJECT! This is just example of ALL options using.
// See the sample project how to use ImageLoader correctly.
File cacheDir = StorageUtils.getCacheDirectory(context);
ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(context)
        .memoryCacheExtraOptions(480, 800) // default = device screen dimensions 圖片內存緩存最大寬高,默認屏幕寬高
        .diskCacheExtraOptions(480, 800, null) //圖片硬盤緩存最大寬高,默認屏幕寬高
        .taskExecutor(...)
        .taskExecutorForCachedImages(...)
        .threadPoolSize(3) // default
        .threadPriority(Thread.NORM_PRIORITY - 2) // default
        .tasksProcessingOrder(QueueProcessingType.FIFO) // default
        .denyCacheImageMultipleSizesInMemory() //默認可以內存緩存會緩存不同尺寸的同一個圖片,此時使用的是FuzzyKeyMemoryCache,會使memoryCache設置無效
        .memoryCache(new LruMemoryCache(2 * 1024 * 1024))
        .memoryCacheSize(2 * 1024 * 1024)
        .memoryCacheSizePercentage(13) // default:1/8 設置內存緩存佔總內存的百分比,memoryCacheSize效果一樣,使用一個就行
        .diskCache(new LruDiskCache(cacheDir)) // default
        .diskCacheSize(50 * 1024 * 1024)
        .diskCacheFileCount(100) //硬盤緩存目錄最大文件個數,默認無限制
        .diskCacheFileNameGenerator(new HashCodeFileNameGenerator()) // default
        .imageDownloader(new BaseImageDownloader(context)) // default
        .imageDecoder(new BaseImageDecoder()) // default
        .defaultDisplayImageOptions(DisplayImageOptions.createSimple()) // default
        .writeDebugLogs()
        .build();

DisplayImageOptions

爲每個任務設置顯示選項,如果DisplayImageOptions爲null,那麼會使用ImageLoaderConfiguration.defaultDisplayImageOptions

/*Display Options (DisplayImageOptions) are local for every display task (ImageLoader.displayImage(...)).
Display Options can be applied to every display task (ImageLoader.displayImage(...) call).
Note: If Display Options wasn't passed to ImageLoader.displayImage(...)method then default Display Options from configuration (ImageLoaderConfiguration.defaultDisplayImageOptions(...)) will be used. */

// DON'T COPY THIS CODE TO YOUR PROJECT! This is just example of ALL options using.
// See the sample project how to use ImageLoader correctly.
DisplayImageOptions options = new DisplayImageOptions.Builder()
        .showImageOnLoading(R.drawable.ic_stub) // resource or drawable
        .showImageForEmptyUri(R.drawable.ic_empty) // resource or drawable
        .showImageOnFail(R.drawable.ic_error) // resource or drawable
        .resetViewBeforeLoading(false)  // default
        .delayBeforeLoading(1000)
        .cacheInMemory(false) // default
        .cacheOnDisk(false) // default
        .preProcessor(...)
        .postProcessor(...)
        .extraForDownloader(...)
        .considerExifParams(false) // default
        .imageScaleType(ImageScaleType.IN_SAMPLE_POWER_OF_2) // default 壓縮圖片選項Options.inSampleSize是否用2的倍數,默認2的倍數
        .bitmapConfig(Bitmap.Config.ARGB_8888) // default
        .decodingOptions(...)
        .displayer(new SimpleBitmapDisplayer()) // default
        .handler(new Handler()) // default
        .build();

UIL在listview, gridview, viewpager中的用法

        //Application中定義全局的配置屬性
        ImageLoaderConfiguration configuration = new ImageLoaderConfiguration.Builder(this)
                .threadPriority(Thread.NORM_PRIORITY - 2) //設置線程優先級
                .denyCacheImageMultipleSizesInMemory() //拒絕內存緩存中緩存不同size的圖片
                .diskCacheFileNameGenerator(new Md5FileNameGenerator()) //硬盤緩存圖片文件名生成器-md5加密,默認HashCodeFileNameGenerator-hashcode
                .diskCacheSize(50 * 1024 * 1024) //硬盤緩存大小50MiB,默認LruDiskCache
                .tasksProcessingOrder(QueueProcessingType.LIFO) //任務後進先出,後面添加的任務先執行,多用於listview等控件,默認FIFO
                .imageDownloader(new BaseImageDownloader(context,10000,20000)) //自定義圖片下載器,設置10s(默認5s)連接超時,20s(默認20s)讀取超時,默認5次重連
                .writeDebugLogs() //打印log信息
                .build(); //其它默認值看ImageLoaderConfiguration的initEmptyFieldsWithDefaultValues方法

        // Initialize ImageLoader with configuration.
        ImageLoader.getInstance().init(configuration);

    private static class ImageAdapter extends BaseAdapter {
        private static final String[] IMAGE_URLS = Constants.IMAGES;
        private LayoutInflater inflater;
        private DisplayImageOptions options;
        ImageAdapter(Context context) {
            inflater = LayoutInflater.from(context);
            options = new DisplayImageOptions.Builder()
                    .showImageOnLoading(R.drawable.ic_stub) //加載中的圖片顯示
                    .showImageForEmptyUri(R.drawable.ic_empty) //url爲null的圖片顯示
                    .showImageOnFail(R.drawable.ic_error) //請求失敗圖片顯示
                    .cacheInMemory(true) //默認false,同時使用LruMemoryCache
                    .cacheOnDisk(true) //默認false,同時使用LruDiskCache
                    .considerExifParams(true) //解碼圖片的時候需要考慮圖片的Exif參數,有些圖片自帶了旋轉縮放等參數
                    .displayer(new CircleBitmapDisplayer(Color.WHITE, 5)) //顯示爲圓形圖片,還有其他形狀的圖片
                    .build();
        }
        @Override
        public int getCount() {
            return IMAGE_URLS.length;
        }
        @Override
        public Object getItem(int position) {
            return position;
        }
        @Override
        public long getItemId(int position) {
            return position;
        }
        @Override
        public View getView(final int position, View convertView, ViewGroup parent) {
            View view = convertView;
            final ViewHolder holder;
            if (convertView == null) {
                view = inflater.inflate(R.layout.item_list_image, parent, false);
                holder = new ViewHolder();
                holder.text = (TextView) view.findViewById(R.id.text);
                holder.image = (ImageView) view.findViewById(R.id.image);
                view.setTag(holder);
            } else {
                holder = (ViewHolder) view.getTag();
            }
            holder.text.setText("Item " + (position + 1));
            ImageLoader.getInstance().displayImage(IMAGE_URLS[position], holder.image, options);
            return view;
        }
    }
    static class ViewHolder {
        TextView text;
        ImageView image;
    }

    //同時注意在activity中,如果被銷燬了,必須手動停止線程池,否則會造成資源的浪費
    @Override
    public void onDestroy() {
        super.onDestroy();
        ImageLoader.getInstance().stop();
    }

不需要setTag,內部實現已經實現了,不會出現錯亂。
pauseOnScroll:Scroll的時候是否加載圖片 pauseOnFling:Fling是否加載圖片

//onMyScrollListener如果需要自己的滾動監視器則這樣使用
listView.setOnScrollListener(new PauseOnScrollListener(ImageLoader.getInstance(), pauseOnScroll, pauseOnFling),onMyScrollListener);

ImageLoader是單例的,listView的滾動事件首先交給OnScrollListener來處理,onScrollStateChanged其中分別調用imageLoader.resume()恢復下載/imageLoader.pause()暫停下載來實現,如果定義了externalListener,那麼就調用externalListener的onScroll/onScrollStateChanged方法.

優點

  1. 多線程下載圖片,圖片可以來源於網絡,文件系統,項目文件夾assets中以及drawable中等
  2. 支持隨意的配置ImageLoader,例如線程池,圖片下載器,內存緩存策略,硬盤緩存策略,圖片顯示選項以及其他的一些配置
  3. 支持圖片的內存緩存,文件系統緩存或者SD卡緩存
  4. 支持圖片下載過程的監聽
  5. 根據控件(ImageView)的大小對Bitmap進行裁剪,減少Bitmap佔用過多的內存
  6. 較好的控制圖片的加載過程,例如暫停圖片加載,重新開始加載圖片,一般使用在ListView,GridView中,滑動過程中暫停加載圖片,停止滑動的時候去加載圖片
  7. 提供在較慢的網絡下對圖片進行加載

Volley並沒有對imageview的大小進行匹配,而是需要自己去定義圖片的顯示大小好麻煩

OutOfMemoryError

雖然這個框架有很好的緩存機制,有效的避免了OOM的產生,一般的情況下產生OOM的概率比較小,但是並不能保證OutOfMemoryError永遠不發生,這個框架對於OutOfMemoryError做了簡單的catch,保證我們的程序遇到OOM而不被crash掉,但是如果我們使用該框架經常發生OOM,我們應該怎麼去改善呢?

  1. 減少線程池中線程的個數,在ImageLoaderConfiguration中的(threadPoolSize)中配置,推薦配置1-5
  2. 在DisplayImageOptions選項中配置bitmapConfig爲Bitmap.Config.RGB_565,因爲默認是ARGB_8888, 使用RGB_565會比使用ARGB_8888少消耗2倍的內存
  3. 在ImageLoaderConfiguration中配置圖片的內存緩存爲memoryCache(new WeakMemoryCache()) 或者不使用內存緩存
  4. 在DisplayImageOptions選項中設置.imageScaleType(ImageScaleType.IN_SAMPLE_INT)或者imageScaleType(ImageScaleType.EXACTLY)

通過上面這些,相信大家對Universal-Image-Loader框架的使用已經非常的瞭解了,我們在使用該框架的時候儘量的使用displayImage()方法去加載圖片,loadImage()是將圖片對象回調到ImageLoadingListener接口的onLoadingComplete()方法中,需要我們手動去設置到ImageView上面,displayImage()方法中,對ImageView對象使用的是Weak references,方便垃圾回收器回收ImageView對象,如果我們要加載固定大小的圖片的時候,使用loadImage()方法需要傳遞一個ImageSize對象,而displayImage()方法會根據ImageView對象的測量值,或者android:layout_width and android:layout_height設定的值,或者android:maxWidth/android:maxHeight設定的值來裁剪圖片

new ImageViewAware(imageView).ImageViewAware內部弱引用指向imageView,這樣就防止了OOM了,如果activity退出,那麼發生GC,那麼會回收該imageview,那麼也就會回收該activity,view內部持有context引用。

簡單流程

簡單的講就是ImageLoader收到加載及顯示圖片的任務,如果是同步的直接運行LoadAndDisplayImageTask任務,如果是異步的,那麼將它交給ImageLoaderEngine線程池管理,ImageLoaderEngine分發任務到具體的線程去執行,任務實際上是通過Cache及ImageDownloader獲取圖片,中間可能經過BitmapProcessor和ImageDecoder處理,最終轉換爲Bitmap交給BitmapDisplayer在ImageAware中顯示。
ImageLoaderEngine:任務分發器,負責分發LoadAndDisplayImageTask和ProcessAndDisplayImageTask給具體的線程池去執行,本文中也稱其爲engine

ImageAware:顯示圖片的對象,可以是ImageView等
ImageDownloader:圖片下載器,負責從圖片的各個來源獲取輸入流
MemoryCache:內存圖片緩存,可向內存緩存緩存圖片或從內存緩存讀取圖片
DiskCache:本地圖片緩存,可向本地磁盤緩存保存圖片或從本地磁盤讀取圖片
ImageDecoder:圖片解碼器,負責將圖片輸入流InputStream轉換爲Bitmap對象
BitmapProcessor:圖片處理器,負責從緩存讀取或寫入前對圖片進行處理,默認是null,如果有需求將圖片設置成圓形的,可以實現該類
BitmapDisplayer:將Bitmap對象顯示在相應的控件ImageAware上
LoadAndDisplayImageTask:用於加載並顯示圖片的任務
ProcessAndDisplayImageTask:用於處理並顯示圖片的任務,跟BitmapProcessor對應,必須定義了BitmapProcessor,但是內部實現其實還是使用LoadAndDisplayImageTask的
DisplayBitmapTask:用於顯示圖片的任務

參考
Android 開源框架Universal-Image-Loader完全解析(一)— 基本介紹及使用
Android Universal Image Loader 源碼分析

發佈了78 篇原創文章 · 獲贊 9 · 訪問量 14萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章