溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶(hù)服務(wù)條款》

Android圖片加載庫(kù)的理解

發(fā)布時(shí)間:2020-07-22 10:37:42 來(lái)源:網(wǎng)絡(luò) 閱讀:343 作者:胡壯壯 欄目:移動(dòng)開(kāi)發(fā)

    

ImageLoader設(shè)計(jì)原理

ImageLoader的工作原理:在顯示圖片的時(shí),它會(huì)先在內(nèi)存中查找,如果沒(méi)有就去本地查找,如果還沒(méi)有,就開(kāi)一個(gè)新的線(xiàn)程去下載這張圖片,下載成功會(huì)把圖片同時(shí)緩存在內(nèi)存和本地。

我們?cè)诨谶@個(gè)原理,在每次退出一個(gè)頁(yè)面時(shí)候,把ImageLoader內(nèi)存中緩存全部清除,這樣就節(jié)省了大量?jī)?nèi)存,反正下次再用到的時(shí)候從本地再取出來(lái)就行了。需要說(shuō)明的是,由于ImageLoader對(duì)圖片是軟引用的形式,所以在內(nèi)存中的圖片會(huì)存在內(nèi)存不足的時(shí)候被系統(tǒng)回收。

總設(shè)計(jì)圖:

Android圖片加載庫(kù)的理解

Android圖片加載庫(kù)的理解

ImageLoader流程圖

Android圖片加載庫(kù)的理解

Android圖片加載庫(kù)的理解

ImageLoader的使用

ImageLoader由三大組件組成:

  1. ImagaLoaderConfiguaration——對(duì)圖片緩存進(jìn)行總體配置,包含內(nèi)存緩存的大小,本地緩存的大小和位置、日志、下載策略(FIFO還是LIFO)等。

  2. ImageLoader——一般使用displayImage來(lái)把URL對(duì)應(yīng)的圖片顯示在ImageView上。

  3. DisplayImageOptions——在每個(gè)頁(yè)面需要顯示圖片的地方,控制如何顯示的細(xì)節(jié),比如指定下載時(shí)的默認(rèn)圖、是否將緩存放到內(nèi)存或本地磁盤(pán)。

從三者的協(xié)作關(guān)系上看,他們有點(diǎn)像廚房規(guī)定、廚師、客戶(hù)個(gè)人口味之間的關(guān)系。ImageLoaderConfiguration就像是廚房里面的規(guī)定,每一個(gè)廚師要怎么著裝,要怎么保持廚房的干凈,這是針對(duì)每一個(gè)廚師都適用的規(guī)定,而且不允許個(gè)性化改變。ImageLoader就像是具體做菜的廚師,負(fù)責(zé)具體菜譜的制作。DisplayImageOptions就像每個(gè)客戶(hù)的偏好,根據(jù)客戶(hù)是重口味還是清淡,每一個(gè)p_w_picpathLoader根據(jù)DisplayImageOptions的要求具體執(zhí)行。

ImagaLoaderConfiguaration

示例代碼:

Android圖片加載庫(kù)的理解

// 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 =newImageLoaderConfiguration.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()
        .memoryCache(newLruMemoryCache(2*1024*1024))
        .memoryCacheSize(2*1024*1024)
        .memoryCacheSizePercentage(13) // default
        .diskCache(newUnlimitedDiskCache(cacheDir)) // default
        .diskCacheSize(50*1024*1024)
        .diskCacheFileCount(100)
        .diskCacheFileNameGenerator(newHashCodeFileNameGenerator()) // default
        .p_w_picpathDownloader(newBaseImageDownloader(context)) // default
        .p_w_picpathDecoder(newBaseImageDecoder()) // default
        .defaultDisplayImageOptions(DisplayImageOptions.createSimple()) // default        .writeDebugLogs()
        .build();

Android圖片加載庫(kù)的理解

可以看到ImagaLoaderConfiguaration的職責(zé)就是記錄相關(guān)的配置,它的內(nèi)部就是一些字段的集合。

DisplayImageOptions

每一個(gè)ImageLoader.displayImage(...)都可以使用DisplayImageOptions,具體配置代碼如下:

Android圖片加載庫(kù)的理解

// 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
        .p_w_picpathScaleType(ImageScaleType.IN_SAMPLE_POWER_OF_2) // default
        .bitmapConfig(Bitmap.Config.ARGB_8888) // default        .decodingOptions(...)
        .displayer(new SimpleBitmapDisplayer()) // default
        .handler(new Handler()) // default
        .build();

Android圖片加載庫(kù)的理解

ImageLoader

最終使用時(shí)候,簡(jiǎn)單幾句就行了,傳入一個(gè)ImageView控件

ImageLoader p_w_picpathLoader = ImageLoader.getInstance(); // Get singleton instance// Load p_w_picpath, decode it to Bitmap and display Bitmap in ImageView (or any other view 
//  which implements ImageAware interface)p_w_picpathLoader.displayImage(p_w_picpathUri, p_w_picpathView);

又或者直接

Android圖片加載庫(kù)的理解

// Load p_w_picpath, decode it to Bitmap and return Bitmap to callbackp_w_picpathLoader.loadImage(p_w_picpathUri, new SimpleImageLoadingListener() {
    @Override    public void onLoadingComplete(String p_w_picpathUri, View view, Bitmap loadedImage) {        // Do whatever you want with Bitmap    }
});

Android圖片加載庫(kù)的理解

ImageLoader優(yōu)化

盡管ImageLoader很強(qiáng)大,但一直把圖片緩存在內(nèi)存中,會(huì)導(dǎo)致內(nèi)存占用過(guò)高。雖然對(duì)圖片的引用是軟引用,軟引用在內(nèi)存不夠的時(shí)候會(huì)被GC,但我們還是希望減少GC的次數(shù),所以要經(jīng)常手動(dòng)清理ImageLoader中的緩存。

比如,我們經(jīng)常在做項(xiàng)目的時(shí)候,會(huì)有一個(gè)AppBaseActivity的基類(lèi),這樣我們可以在基類(lèi)的onDestroy方法中,執(zhí)行ImageLoader的clearMemoryCache方法,以確保頁(yè)面銷(xiāo)毀時(shí),把為了顯示這個(gè)頁(yè)面而增加的內(nèi)存緩存清除,這樣即使到了下個(gè)頁(yè)面要復(fù)用之前加載過(guò)的圖片,雖然內(nèi)存沒(méi)有了,根據(jù)ImageLoader的緩存策略,在本地磁盤(pán)上還是能被找到的。

比如:

 

protected void onDestroy() {        //回收該頁(yè)面緩存在內(nèi)存的圖片        p_w_picpathLoader.clearMemoryCache(); 
        super.onDestroy();
}

Fresco介紹

簡(jiǎn)介:

Fresco 是一個(gè)強(qiáng)大的圖片加載組件。它是Facebook開(kāi)源的圖片加載庫(kù)

Fresco 中設(shè)計(jì)有一個(gè)叫做 p_w_picpath pipeline 的模塊。它負(fù)責(zé)從網(wǎng)絡(luò),從本地文件系統(tǒng),本地資源加載圖片。為了最大限度節(jié)省空間和CPU時(shí)間,它含有3級(jí)緩存設(shè)計(jì)(2級(jí)內(nèi)存,1級(jí)文件)。

Fresco 中設(shè)計(jì)有一個(gè)叫做 Drawees 模塊,方便地顯示loading圖,當(dāng)圖片不再顯示在屏幕上時(shí),及時(shí)地釋放內(nèi)存和空間占用。

Fresco 支持 Android2.3(API level 9) 及其以上系統(tǒng)。

 

流程圖:

Android圖片加載庫(kù)的理解

 

Android圖片加載庫(kù)的理解

 

原理:

Fresco 設(shè)計(jì)了p_w_picpath pipeline 的概念,它負(fù)責(zé)先后檢查內(nèi)存,磁盤(pán)文件,如果都沒(méi)有再老老實(shí)實(shí)從網(wǎng)絡(luò)下載圖片。

主要有個(gè)三層緩存的概念

第一層:Bitmap緩存

在Android 5.0系統(tǒng)中,考慮到內(nèi)存管理有了很大改進(jìn),所以 Bitmap緩存位于Java的heap中,而在Android 4.X或更低的系統(tǒng)中,Bitmap緩存位于ashmem中,而不是位于Java的heap中,這意味著圖片的創(chuàng)建和回收不會(huì)引發(fā)過(guò)多的GC,從而讓APP運(yùn)行的更快。

第二層:內(nèi)存緩存

內(nèi)存緩存中存儲(chǔ)了圖片的原始?jí)嚎s格式,從內(nèi)存緩存中取出的圖片,在顯示前必須先解碼,當(dāng)APP切換到后臺(tái)時(shí),內(nèi)存緩存也會(huì)被清空。

第三層:磁盤(pán)緩存

又名本地緩存,磁盤(pán)緩存中存儲(chǔ)的也是圖片的原始?jí)嚎s格式,在使用前也要先解碼,當(dāng)APP切換到后臺(tái)時(shí),磁盤(pán)緩存不會(huì)丟失,即使關(guān)機(jī)也不會(huì)。

 

使用:

為了下載網(wǎng)絡(luò)圖片,請(qǐng)確保在 AndroidManifest.xml 中有以下權(quán)限:

<uses-permission android:name="android.permission.INTERNET"/>

在 Application 初始化時(shí),在應(yīng)用調(diào)用 setContentView() 之前,進(jìn)行初始化:

Fresco.initialize(context);

在xml布局文件中, 加入命名空間:

Android圖片加載庫(kù)的理解

<!-- 其他元素 --><LinearLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:fresco="http://schemas.android.com/apk/res-auto">加入SimpleDraweeView:<com.facebook.drawee.view.SimpleDraweeView    android:id="@+id/my_p_w_picpath_view"
    android:layout_width="20dp"
    android:layout_height="20dp"
    fresco:placeholderImage="@drawable/my_drawable"
  />

Android圖片加載庫(kù)的理解

開(kāi)始加載圖片

Uri uri = Uri.parse("https://raw.githubusercontent.com/facebook/fresco/gh-pages/static/fresco-logo.png");
SimpleDraweeView draweeView = (SimpleDraweeView) findViewById(R.id.my_p_w_picpath_view);
draweeView.setImageURI(uri);

圖片策略?xún)?yōu)化

我們這里說(shuō)的圖片,是根據(jù)服務(wù)端的接口返回的圖片URL地址開(kāi)啟一個(gè)線(xiàn)程下載到APP本地并顯示的,很多APP崩潰的原因就是圖片的問(wèn)題沒(méi)處理好。那么就有一些相關(guān)解決方案策略,如下。

  1. 要確保下載的每張圖,都符合ImageView控件的大小??梢允孪葴?zhǔn)備很多套不同的分辨率的圖片,然后每次根據(jù)URL請(qǐng)求圖片時(shí),都要額外在URL上加兩個(gè)參數(shù),width和height,從而要求服務(wù)器返回其中某一個(gè)張圖,比如:http://www.aaa.com/a.png?width=100&height=50

  2. 低流量模式。在2G和3G網(wǎng)絡(luò)環(huán)境下,我們應(yīng)該適當(dāng)降低圖片的質(zhì)量,降低圖片質(zhì)量,相應(yīng)的圖片大小也會(huì)降低,簡(jiǎn)稱(chēng)低流量模式,比如在請(qǐng)求網(wǎng)址中再添加一個(gè)參數(shù),叫做quality,在2G網(wǎng)絡(luò)下這個(gè)值為50%,在3G網(wǎng)絡(luò)情況下,這個(gè)值為70%,這樣就會(huì)將JPG圖片質(zhì)量降低為50%或70%。

  3. 極速模式。發(fā)現(xiàn)在2G和3G網(wǎng)絡(luò)環(huán)境下,大部分用戶(hù)對(duì)圖片不感興趣,我們可以設(shè)計(jì)一些只有文字的頁(yè)面,這種頁(yè)面稱(chēng)呼為極速模式,以節(jié)省流量。

小結(jié)

本篇主要介紹了第三方圖片加載庫(kù)的原理和使用方法,特別是ImageLoader的介紹,因?yàn)閳D片顯示在APP中是很常見(jiàn)的應(yīng)用場(chǎng)景,況且ImageLoader已經(jīng)封裝好了一些類(lèi)和方法。我們可以直接拿來(lái)用了。而不用重復(fù)去寫(xiě)了。如果自己去寫(xiě)一個(gè)的話(huà),這方面的程序還是比較麻煩的,要考慮多線(xiàn)程緩存,內(nèi)存溢出等很多方面,再說(shuō)這么多程序都在用,說(shuō)明穩(wěn)定性還是可靠的,類(lèi)似這種工具類(lèi)能用穩(wěn)定成熟的,我們作為一名開(kāi)發(fā)人員,專(zhuān)注度還是在應(yīng)用業(yè)務(wù)開(kāi)發(fā)上。


向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI