Android之解析加載大圖

現在的世界是圖片的世界,一切都只看如,就像“沒圖沒真相”、“沒圖你說個XX”
可是圖片有這么多,高清圖片這么大,Android手機的內存又有限,用有限的內存加載無限大的圖片,這是一個很嚴峻的問題,所以大圖加載技術應運而生。

我們先看加載大圖的全部代碼,然后在細細解析代碼的意思吧!

public class MainActivity extends Activity {

private ImageView iv;
private int screenWidth;
private int screenHeight;

@SuppressWarnings("deprecation")
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    
    //[1]找到iv 顯示加載圖片        
    iv = (ImageView) findViewById(R.id.iv);
    
    //[2]獲取手機的分辨率  獲取windowmanager 實例 
    WindowManager wm  = (WindowManager) getSystemService(WINDOW_SERVICE);
    // 用于android 8以上
    screenWidth = wm.getDefaultDisplay().getWidth();
    screenHeight = wm.getDefaultDisplay().getHeight();      
    // 只能用于android 13以上
    //Point outSize = new Point();
    //wm.getDefaultDisplay().getSize(outSize);
    //screenWidth = outSize.x;
    //screenHeight = outSize.y;
    
    System.out.println("手機的寬和高:"+screenWidth+"---"+screenHeight);
}

//點擊按鈕  加載dog.jpg 這張圖片
@SuppressLint("SdCardPath")
public void click(View v) {
    //[2]把xxxx.jpg 轉換成bitmap  
    
    //創建bitmap工廠的配置參數 
    BitmapFactory.Options options = new Options();
    
    //返回一個null 沒有bitmap   不去真正解析位圖 但是能返回圖片的一些信息(寬和高)
    options.inJustDecodeBounds = true;
    BitmapFactory.decodeFile("/mnt/sdcard/xxxx.jpg",options);
    //[3]獲取圖片的寬和高  
    int imgWidth = options.outWidth;
    int imgHeight = options.outHeight;
    System.out.println("圖片的寬:"+imgWidth+"-----"+imgHeight);
    
    //[4]計算縮放比 
    int scale = 1;  //我們定義的縮放比 
    int scalex =  imgWidth/screenWidth;
    int scaley = imgHeight /screenHeight;
    if (scalex >=scaley&&scalex > scale) {
        scale = scalex;
    }
    if (scaley > scalex && scaley>scale) {
        scale = scaley;
    }
    System.out.println("縮放比為:"+scale);      
    
    //[5]按照縮放比顯示圖片 
    options.inSampleSize = scale;
    
    //[6]開始真正的解析位圖 
    options.inJustDecodeBounds = false;
    Bitmap bitmap = BitmapFactory.decodeFile("/mnt/sdcard/dog.jpg",options);
    
    //[7]把bitmap顯示到控件上
    iv.setImageBitmap(bitmap);  
}
}

好了,上面就是解碼大圖Demo的全部代碼了。
我們首先獲得屏幕的大小,然后獲得圖片的大小,最后通過計算屏幕與圖片的縮放比,按照縮放比來解析位圖。

其中有兩個方法比較重要,在這里我們進行解析:

options.inJustDecodeBounds

這一個方法的意思是,如果給它賦值true,那么它就不會解析圖片,如果不解析圖片,那么我們就不能夠將圖片展示在手機屏幕之中。
使用它的目的是為了獲得圖片的一些信息,如圖片高度和寬度,然后進行下一步工作,也就是計算縮放比。
重點,在計算好縮放比(options.inSampleSize)之后不要忘記將options.inJustDecodeBounds設置為false,否則仍然不會展示圖片。

options.inSampleSize 

這一個方法是給圖片賦予縮放比,當它的值大于1的時候,它就會按照縮放比返回一個小圖片用來節省內存。舉個例子,如果她的值為4,那么返回的圖片大小將會是原始高度和寬度的1/4大小。
如果它的值小于1的話,不會有任何的效果。
順便友情提示options.inSampleSize的值最后會按照2的倍數來進行縮放,所以最好將縮放值設置為2的倍數。

關于計算縮放比的問題,在上面的代碼中我們是直接通過圖片高寬/屏幕高寬計算的,縮放比的值這是通過比較高度縮放比和寬度縮放比,那個數值大就取哪一個。
當然,這不是唯一的算法,也可以制定自己的算法。

補充說明:
計算縮放比,也就是inSampleSize的值的方式被 mcarthorlee 大神批評了,不過大神也說的對,

如果屏幕是1280720,圖片大小是1300800,那你算出來的inSampleSize就是1,完全沒有縮小。

為了讓大家不被我的計算方式誤導,這里也放出Android提供的縮放比計算方法:

public static int calculateInSampleSize(BitmapFactory.Options options,
        int reqWidth, int reqHeight) {
    // Raw height and width of image
    final int height = options.outHeight;
    final int width = options.outWidth;
    int inSampleSize = 1;

    if (height > reqHeight || width > reqWidth) {

        final int halfHeight = height / 2;
        final int halfWidth = width / 2;

        // Calculate the largest inSampleSize value that is a power of 2 and
        // keeps both
        // height and width larger than the requested height and width.
        while ((halfHeight / inSampleSize) >= reqHeight &&
                (halfWidth / inSampleSize) >= reqWidth) {
            inSampleSize *= 2;
        }
    }

    return inSampleSize;
}

在這個方法中,我們只需要提供圖片的元數據options提供進去,然后填入自己想獲得圖片的寬高的數值,然后就能夠計算出縮放比。

Android官方關于加載大圖的技術指導:

https://developer.android.com/training/displaying-bitmaps/load-bitmap.html#

對大圖需要特殊處理的原因

要對大圖進行處理除了因為圖片大小自身的原因之外,還有Android對圖片解碼的因素在內。

比如一張寬度2400px,高度為3200px的jpg格式的圖片,假設它現在的大小為3mb,但是如果我們直接在android中解碼,使用以下代碼:

BitmapFactory.decodeFile("bigImage.jpg");

那么結果會怎樣呢?

Android在解碼這種圖片的時候會申請29MB左右的內存來進行解碼。

這是怎么回事呢?

因為圖片的大小 = 圖片總像素 * 圖片當個像素的大小

在Android中使用ARGB來展示顏色的,一般情況下使用的是ARGB_8888,每個像素的大小約為4byte。

每個像素4 byte的是ARGB_8888,還有一個ARGB_4444是2 byte,RGB_565也是2 byte。

詳情請看官方文檔:

https://developer.android.com/reference/android/graphics/Bitmap.Config.html

所以上面的寬2400px,高3200px的大圖在Android中解碼出來的大小的計算公式:

2400 * 3200 * 4 = 30720000byte

換算成mb,大小為29mb左右。

這就無怪乎Android需要為加載大圖做出特殊的處理了,就這么一張大小為2mb的jpg圖片解碼出來就有29mb,那么其他圖片一起解碼出來,Android的內存怎么夠用!

以上為作者對Android加載大圖的個人理解,如有錯漏之處,請不吝賜教!

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,156評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,401評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,069評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,873評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,635評論 6 408
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,128評論 1 323
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,203評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,365評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,881評論 1 334
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,733評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,935評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,475評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,172評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,582評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,821評論 1 282
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,595評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,908評論 2 372

推薦閱讀更多精彩內容