日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > Android >内容正文

Android

Android官方开发文档Training系列课程中文版:高效显示位图之加载大位图

發布時間:2024/7/5 Android 48 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Android官方开发文档Training系列课程中文版:高效显示位图之加载大位图 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

原文地址:http://android.xsoftlab.net/training/displaying-bitmaps/index.html

引言

學習如何使用一種常規的手段來處理及加載Bitmap對象,這種方式除了使用戶界面是可響應的之外,還會避免超出內存的限制。如果你不小心點的話,位圖會迅速的將那些可憐的內存消耗殆盡,并會導致程序崩潰,因為這會產生一種可怕的異常:

java.lang.OutofMemoryError: bitmap size exceeds VM budget.

這里列舉出了一些原因來說明為什么加載位圖對于Android程序來說是非常棘手的:

  • 移動設備通常含有有限的資源。Android設備對于單個程序只有少量的16MB可用內存。虛擬機兼容性(Virtual Machine Compatibility)針對于各種的屏幕尺寸和密度給出了最低限度的程序內存要求。程序應該在極小的內存空間下充分利用內存空間。無論如何要記住一點,很多設備配備了更高的限制。
  • 位圖通常會消耗掉不少內存,尤其是豐富的圖片,就像照片這樣的。舉個例子,Galaxy Nexus上的相機拍的照片會達到2592x1936個像素(五百萬像素)。如果位圖配置使用的是ARGB_8888(這在Android 2.3以前是默認的),那么加載這張照片到內存中就需要花費掉19MB的內存(2592*1936*4個字節),這會立即耗盡某些設備上的所有內存。
  • Android的APP界面有時會很頻繁的請求一些圖片來加載。有些組件比如ListView, GridView及ViewPager,它們有個共同的特性就是需要同時在屏幕上加載多個位圖并會在屏幕之外的地方加載以便在手指滑動的時候顯示出來。

有效加載大圖

圖片會有各種形狀和大小。在很多情況下它們會比用戶界面上所要求的尺寸要大。舉個例子,系統的相冊應用所展示的用相機拍攝的照片的分辨率通常要比屏幕的密度要高。

鑒于在有限的內存中工作,理想上只用加載低分辨率的版本就可以。低分辨率的版本應該匹配到展示這張圖片的控件大小。圖片的更高分辨率不會在視覺上有更佳的效果,但是這仍然會消耗寶貴的內存空間,由于額外的動態擴展,這會招致額外的性能開銷。

這節課會討論將大位圖進行二次采樣并將采樣后的小版本加載到內存中的過程。這個過程并不會超出應用的內存限制。

讀取位圖的尺寸及類型

類BitmapFactory提供了若干個解碼方法(decodeByteArray(), decodeFile(), decodeResource(), etc.)根據不同的資源來創建位圖Bitmap。選擇更加適合的解碼方法取決于圖片的數據資源。這些方法會在構造位圖時嘗試向內存申請空間,所以會輕易的造成OutOfMemory異常。每個解碼方法都有一個附屬特征,這個特征可以使你通過BitmapFactory.Options類來指定解碼選項。設置inJustDecodeBounds屬性為true可以避免在解碼時向內存申請空間,這會返回一個空的位圖,但是outWidth、outHeight和outMimeType這些設置除外。這項技術可以使你在構造位圖(申請內存)之前提前讀取圖像數據的尺寸及類型。

BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeResource(getResources(), R.id.myimage, options); int imageHeight = options.outHeight; int imageWidth = options.outWidth; String imageType = options.outMimeType;

為了避免java.lang.OutOfMemory異常,需要在解碼圖片之前檢查圖片的尺寸,除非你對這些圖像數據的尺寸絕對的信任,并且該尺寸對可用內存非常適用。

加載等比縮小的版本到內存

那么現在圖片的尺寸是知道了,這尺寸可以被用來決定:是否全尺寸的圖像應該被加載到內存中還是應該有個二次采樣的版本加載到內存中。這里有一些因素需要考慮:

  • 往內存中加載全尺寸的圖像應該估算要使用的內存大小。
  • 要加載的圖片所需要的內存數量需要給應用預留一定的內存空間,不要消耗完全。
  • ImageView或者UI組件的尺寸是圖像將要加載的尺寸。
  • 當前設備的屏幕尺寸與密度。

舉個例子,加載一個1024*768像素的圖片到內存中是沒有價值的,如果這個圖片最終被顯示為一個128x96像素的縮略圖的話。

為了告訴解碼器需要進行二次采樣,以便加載一個小版本的圖像到內存中,需要設置BitmapFactory.Options對象的inSampleSize屬性為true。舉個例子,一張圖片的分辨率為2048x1536,需要通過inSampleSize解碼為4分之一大小的位圖,大概是512x384。加載這樣的圖像只需要花費0.75MB內存,而全尺寸的圖像則需要花費12MB的內存(假設位圖的配置為ARGB_8888)。這里有一個方法可以來計算一個樣本容量值,這個值是2的冪次方值并基于原圖像的高度值與寬度值進行計算。

public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {// Raw height and width of imagefinal 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; }

Note: 最終計算后的值是一個2的冪次方值是因為解碼器需要通過舍入來獲得一個最終值,這個值與2的冪次方最為接近,依據inSampleSize文檔。

為了使用這個方法,第一步需要將inJustDecodeBounds設置為true,然后將options交給BitmapFactory使用,然后再次使用一個新的inSampleSize和inJustDecodeBounds設置為false來再次使用:

public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,int reqWidth, int reqHeight) {// First decode with inJustDecodeBounds=true to check dimensionsfinal BitmapFactory.Options options = new BitmapFactory.Options();options.inJustDecodeBounds = true;BitmapFactory.decodeResource(res, resId, options);// Calculate inSampleSizeoptions.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);// Decode bitmap with inSampleSize setoptions.inJustDecodeBounds = false;return BitmapFactory.decodeResource(res, resId, options); }

這個方法可以很輕易的加載任何大尺寸的位圖給ImageView,這個ImageView展示了一個100*100像素的縮略圖,就像下面的代碼所展示的這樣:

mImageView.setImageBitmap(decodeSampledBitmapFromResource(getResources(), R.id.myimage, 100, 100));

你可以遵循類似的過程來對其它資源進行解碼,如果需要的話,可以替代使用合適的BitmapFactory.decode*方法。

總結

以上是生活随笔為你收集整理的Android官方开发文档Training系列课程中文版:高效显示位图之加载大位图的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。