參考資料
目錄
- Bitmap
- BitmapFactory
- Bitmap加載方法
- Bitmap | Drawable | InputStream | Byte[ ] 之間轉(zhuǎn)換
- Bitmap常用操作
- Bitmap的內(nèi)存優(yōu)化
1)Bitmap
Bitmap圖像處理的最重要類之一坏晦。用它可以獲取圖像文件信息融求,進行圖像顏色變換尚蝌、剪切慎菲、旋轉(zhuǎn)、縮放等操作某饰,并可以指定格式保存圖像文件
方法 | 說明 |
---|---|
public void recycle() | 回收位圖占用的內(nèi)存空間 |
public final boolean isRecycled() | 判斷位圖內(nèi)存是否已釋放 |
public final int getWidth() | 獲取位圖的寬度 |
public final int getHeight() | 獲取位圖的高度 |
public final boolean isMutable() | 圖片是否可修改 |
public int getScaledWidth(Canvas canvas) | 獲取指定密度轉(zhuǎn)換后的圖像的寬度 |
public int getScaledHeight(Canvas canvas) | 獲取指定密度轉(zhuǎn)換后的圖像的高度 |
public boolean compress(CompressFormat format, int quality, OutputStream stream) | 按指定的圖片格式以及畫質(zhì)些膨,將圖片轉(zhuǎn)換為輸出流 format:壓縮圖像的格式,如Bitmap.CompressFormat.PNG或Bitmap.CompressFormat.JPEG quality:畫質(zhì)喇澡,0-100.0表示最低畫質(zhì)壓縮浦马,100以最高畫質(zhì)壓縮时呀。對于PNG等無損格式的圖片张漂,會忽略此項設(shè)置。 stream: OutputStream中寫入壓縮數(shù)據(jù)谨娜。 return: 是否成功壓縮到指定的流鹃锈。 |
public static Bitmap createBitmap(Bitmap src) | 以src為原圖生成不可變得新圖像 |
public static Bitmap createScaledBitmap(Bitmap src, int dstWidth, int dstHeight, boolean filter) | 以src為原圖,創(chuàng)建新的圖像瞧预,指定新圖像的高寬以及是否可變 |
public static Bitmap createBitmap(int width, int height, Config config) | 創(chuàng)建指定格式、大小的位圖 |
public static Bitmap createBitmap(Bitmap source, int x, int y, int width, int height) | 以source為原圖仅政,創(chuàng)建新的圖片垢油,指定起始坐標(biāo)以及新圖像的高寬 |
2) BitmapFactory
Option 參數(shù)類:
Option 參數(shù)類方法 | 說明 |
---|---|
public boolean inJustDecodeBounds | 如果設(shè)置為true,不獲取圖片圆丹,不分配內(nèi)存滩愁,但會返回圖片的高度寬度信息 |
public int inSampleSize | 圖片縮放的倍數(shù) |
public int outWidth | 獲取圖片的寬度值 |
public int outHeight | 獲取圖片的高度值 |
public int inDensity | 用于位圖的像素壓縮比 |
public int inTargetDensity | 用于目標(biāo)位圖的像素壓縮比(要生成的位圖) |
public byte[] inTempStorage | 創(chuàng)建臨時文件,將圖片存儲 |
public boolean inScaled | 設(shè)置為true時進行圖片壓縮辫封,從inDensity到inTargetDensity |
public boolean inDither | 如果為true,解碼器嘗試抖動解碼 |
public Bitmap.Config inPreferredConfig | 設(shè)置解碼器 這個值是設(shè)置色彩模式硝枉,默認值是ARGB_8888,在這個模式下倦微,一個像素點占用4bytes空間妻味,一般對透明度不做要求的話,一般采用RGB_565模式欣福,這個模式下一個像素點占用2bytes |
public String outMimeType | 設(shè)置解碼圖像 |
public boolean inPurgeable | 當(dāng)存儲Pixel的內(nèi)存空間在系統(tǒng)內(nèi)存不足時是否可以被回收 |
public boolean inInputShareable | inPurgeable為true情況下才生效责球,是否可以共享一個InputStream |
public boolean inPreferQualityOverSpeed | 為true則優(yōu)先保證Bitmap質(zhì)量其次是解碼速度 |
public boolean inMutable | 配置Bitmap是否可以更改,比如:在Bitmap上隔幾個像素加一條線段 |
public int inScreenDensity | 當(dāng)前屏幕的像素密度 |
工廠方法:
方法 | 說明 |
---|---|
public static Bitmap decodeFile(String pathName, Options opts) public static Bitmap decodeFile(String pathName) |
從文件讀取圖片 |
public static Bitmap decodeFileDescriptor(FileDescriptor fd) public static Bitmap decodeFileDescriptor(FileDescriptor fd, Rect outPadding, Options opts) |
從文件讀取文件 與decodeFile不同的是這個直接調(diào)用JNI函數(shù)進行讀取 效率比較高 |
public static Bitmap decodeStream(InputStream is) public static Bitmap decodeStream(InputStream is, Rect outPadding, Options opts) |
從輸入流讀取圖片 |
public static Bitmap decodeStream(InputStream is, Rect outPadding, Options opts) public static Bitmap decodeResource(Resources res, int id) public static Bitmap decodeResource(Resources res, int id, Options opts) |
從資源文件讀取圖片 |
public static Bitmap decodeByteArray(byte[] data, int offset, int length) public static Bitmap decodeByteArray(byte[] data, int offset, int length, Options opts) |
從數(shù)組讀取圖片 |
Bitmap.Config inPreferredConfig 枚舉變量 (位圖位數(shù)越高代表其可以存儲的顏色信息越多拓劝,圖像越逼真雏逾,占用內(nèi)存越大)
常量 | 說明 |
---|---|
public static final Bitmap.Config ALPHA_8 | 代表8位Alpha位圖 每個像素占用1byte內(nèi)存 |
public static final Bitmap.Config ARGB_4444 | 代表16位ARGB位圖 每個像素占用2byte內(nèi)存 |
public static final Bitmap.Config ARGB_8888 | 代表32位ARGB位圖 每個像素占用4byte內(nèi)存 |
public static final Bitmap.Config RGB_565 | 代表8位RGB位圖 每個像素占用2byte內(nèi)存 |
3) Bitmap加載方法
- 從本地(SDcard)文件讀取
public static Bitmap readBitmapFromFileDescriptor(String filePath, int width, int height) {
try {
FileInputStream fis = new FileInputStream(filePath);
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFileDescriptor(fis.getFD(), null, options);
float srcWidth = options.outWidth;
float srcHeight = options.outHeight;
int inSampleSize = 1;
if (srcHeight > height || srcWidth > width) {
if (srcWidth > srcHeight) {
inSampleSize = Math.round(srcHeight / height);
} else {
inSampleSize = Math.round(srcWidth / width);
}
}
options.inJustDecodeBounds = false;
options.inSampleSize = inSampleSize;
return BitmapFactory.decodeFileDescriptor(fis.getFD(), null, options);
} catch (Exception ex) {
}
return null;
}
- 從輸入流讀取文件(網(wǎng)絡(luò)加載)
public static Bitmap readBitmapFromInputStream(InputStream ins, int width, int height) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeStream(ins, null, options);
float srcWidth = options.outWidth;
float srcHeight = options.outHeight;
int inSampleSize = 1;
if (srcHeight > height || srcWidth > width) {
if (srcWidth > srcHeight) {
inSampleSize = Math.round(srcHeight / height);
} else {
inSampleSize = Math.round(srcWidth / width);
}
}
options.inJustDecodeBounds = false;
options.inSampleSize = inSampleSize;
return BitmapFactory.decodeStream(ins, null, options);
}
- Resource資源加載
此種方式相當(dāng)?shù)暮馁M內(nèi)存 建議采用通過InputStream ins = resources.openRawResource(resourcesId);
然后使用decodeStream代替decodeResource
public static Bitmap readBitmapFromResource(Resources resources, int resourcesId, int width, int height) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(resources, resourcesId, options);
float srcWidth = options.outWidth;
float srcHeight = options.outHeight;
int inSampleSize = 1;
if (srcHeight > height || srcWidth > width) {
if (srcWidth > srcHeight) {
inSampleSize = Math.round(srcHeight / height);
} else {
inSampleSize = Math.round(srcWidth / width);
}
}
options.inJustDecodeBounds = false;
options.inSampleSize = inSampleSize;
return BitmapFactory.decodeResource(resources, resourcesId, options);
}
BitmapFactory.decodeResource 加載的圖片可能會經(jīng)過縮放,該縮放目前是放在 java 層做的郑临,效率比較低栖博,而且需要消耗 java 層的內(nèi)存。因此厢洞,如果大量使用該接口加載圖片仇让,容易導(dǎo)致OOM錯誤
BitmapFactory.decodeStream 不會對所加載的圖片進行縮放,相比之下占用內(nèi)存少犀变,效率更高妹孙。
這兩個接口各有用處,如果對性能要求較高获枝,則應(yīng)該使用 decodeStream蠢正;如果對性能要求不高,且需要 Android 自帶的圖片自適應(yīng)縮放功能省店,則可以使用 decodeResource嚣崭。
- Assets資源加載方式
public static Bitmap readBitmapFromAssetsFile(Context context, String filePath) {
Bitmap image = null;
AssetManager am = context.getResources().getAssets();
try {
InputStream is = am.open(filePath);
image = BitmapFactory.decodeStream(is);
is.close();
} catch (IOException e) {
e.printStackTrace();
}
return image;
}
- 從二進制數(shù)據(jù)讀取圖片
public static Bitmap readBitmapFromByteArray(byte[] data, int width, int height) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeByteArray(data, 0, data.length, options);
float srcWidth = options.outWidth;
float srcHeight = options.outHeight;
int inSampleSize = 1;
if (srcHeight > height || srcWidth > width) {
if (srcWidth > srcHeight) {
inSampleSize = Math.round(srcHeight / height);
} else {
inSampleSize = Math.round(srcWidth / width);
}
}
options.inJustDecodeBounds = false;
options.inSampleSize = inSampleSize;
return BitmapFactory.decodeByteArray(data, 0, data.length, options);
}
4) Bitmap | Drawable | InputStream | Byte[ ] 之間進行轉(zhuǎn)換
- Drawable -> Bitmap
public static Bitmap drawableToBitmap(Drawable drawable) {
Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), drawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565);
Canvas canvas = new Canvas(bitmap);
drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
drawable.draw(canvas);
return bitmap;
}
- Bitmap -> Drawable
public static Drawable bitmapToDrawable(Resources resources, Bitmap bm) {
Drawable drawable = new BitmapDrawable(resources, bm);
return drawable;
}
- Bitmap -> byte[]
public byte[] bitmap2Bytes(Bitmap bm) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bm.compress(Bitmap.CompressFormat.PNG, 100, baos);
return baos.toByteArray();
}
- byte[] -> Bitmap
Bitmap bitmap = BitmapFactory.decodeByteArray(byte, 0, b.length);
- InputStream -> Bitmap
InputStream is = getResources().openRawResource(id);
Bitmap bitmap = BitmaoFactory.decodeStream(is);
- Bitmap -> InputStream
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bm.compress(Bitmap.CompressFormat.PNG, 100, baos);
InputStream isBm = new ByteArrayInputStream(baos.toByteArray());
- InputStream -> byte[]
InputStream is = getResources().openRawResource(id);//也可以通過其他方式接收一個InputStream對象
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] b = new byte[1024*2];
int len = 0;
while ((len = is.read(b, 0, b.length)) != -1)
{
baos.write(b, 0, len);
baos.flush();
}
byte[] bytes = baos.toByteArray();
5) Bitmap常用操作
- 將Bitmap保存為本地文件
public static void writeBitmapToFile(String filePath, Bitmap b, int quality) {
try {
File desFile = new File(filePath);
FileOutputStream fos = new FileOutputStream(desFile);
BufferedOutputStream bos = new BufferedOutputStream(fos);
b.compress(Bitmap.CompressFormat.JPEG, quality, bos);
bos.flush();
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
- 圖片壓縮
private static Bitmap compressImage(Bitmap image) {
if (image == null) {
return null;
}
ByteArrayOutputStream baos = null;
try {
baos = new ByteArrayOutputStream();
image.compress(Bitmap.CompressFormat.JPEG, 100, baos);
byte[] bytes = baos.toByteArray();
ByteArrayInputStream isBm = new ByteArrayInputStream(bytes);
Bitmap bitmap = BitmapFactory.decodeStream(isBm);
return bitmap;
} catch (OutOfMemoryError e) {
} finally {
try {
if (baos != null) {
baos.close();
}
} catch (IOException e) {
}
}
return null;
}
- 圖片縮放
/**
* 根據(jù)scale生成一張圖片
*
* @param bitmap
* @param scale 等比縮放值
* @return
*/
public static Bitmap bitmapScale(Bitmap bitmap, float scale) {
Matrix matrix = new Matrix();
matrix.postScale(scale, scale); // 長和寬放大縮小的比例
Bitmap resizeBmp = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
return resizeBmp;
}
- 獲取圖片旋轉(zhuǎn)角度
/**
* 讀取照片exif信息中的旋轉(zhuǎn)角度
*
* @param path 照片路徑
* @return角度
*/
private static int readPictureDegree(String path) {
if (TextUtils.isEmpty(path)) {
return 0;
}
int degree = 0;
try {
ExifInterface exifInterface = new ExifInterface(path);
int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
switch (orientation) {
case ExifInterface.ORIENTATION_ROTATE_90:
degree = 90;
break;
case ExifInterface.ORIENTATION_ROTATE_180:
degree = 180;
break;
case ExifInterface.ORIENTATION_ROTATE_270:
degree = 270;
break;
}
} catch (Exception e) {
}
return degree;
}
- 設(shè)置圖片旋轉(zhuǎn)角度
private static Bitmap rotateBitmap(Bitmap b, float rotateDegree) {
if (b == null) {
return null;
}
Matrix matrix = new Matrix();
matrix.postRotate(rotateDegree);
Bitmap rotaBitmap = Bitmap.createBitmap(b, 0, 0, b.getWidth(), b.getHeight(), matrix, true);
return rotaBitmap;
}
- 控件轉(zhuǎn)為Bitmap
public static Bitmap convertViewToBitMap(View view){
// 打開圖像緩存
view.setDrawingCacheEnabled(true);
// 必須調(diào)用measure和layout方法才能成功保存可視組件的截圖到png圖像文件
// 測量View大小
view.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
// 發(fā)送位置和尺寸到View及其所有的子View
view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight());
// 獲得可視組件的截圖
Bitmap bitmap = view.getDrawingCache();
return bitmap;
}
public static Bitmap getBitmapFromView(View view){
Bitmap returnedBitmap = Bitmap.createBitmap(view.getWidth(), view.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(returnedBitmap);
Drawable bgDrawable = view.getBackground();
if (bgDrawable != null)
bgDrawable.draw(canvas);
else
canvas.drawColor(Color.WHITE);
view.draw(canvas);
return returnedBitmap;
}
- 圓角圖片
ImageView img = (ImageView) findViewById(R.id.img);
Bitmap mBitmap = BitmapFactory.decodeResource(getResources(),R.drawable.def);
Bitmap bmp = Bitmap.createBitmap(mBitmap.getWidth(),mBitmap.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bmp);
Paint mPaint = new Paint();
mPaint.setAntiAlias(true);
RectF rectF = new RectF(0,0,mBitmap.getWidth(),mBitmap.getHeight());
canvas.drawRoundRect(rectF,mBitmap.getWidth()/2,mBitmap.getHeight()/2,mPaint);
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
canvas.drawBitmap(mBitmap,0,0,mPaint);
img.setImageBitmap(bmp);
- 對 bitmap 進行裁剪
public Bitmap bitmapClip(Context context , int id , int x , int y){
Bitmap map = BitmapFactory.decodeResource(context.getResources(), id);
map = Bitmap.createBitmap(map, x, y, 120, 120);
return map;
}
6) Bitmap的內(nèi)存優(yōu)化
在Android應(yīng)用里笨触,最耗費內(nèi)存的就是圖片資源。而且在Android系統(tǒng)中雹舀,讀取位圖Bitmap時芦劣,分給虛擬機中的圖片的堆棧大小只有8M,如果超出了说榆,就會出現(xiàn)OutOfMemory異常虚吟。所以,對于圖片的內(nèi)存優(yōu)化签财,是Android應(yīng)用開發(fā)中比較重要的內(nèi)容串慰。
- 要及時回收Bitmap的內(nèi)存
Bitmap類有一個方法recycle(),從方法名可以看出意思是回收唱蒸。這里就有疑問了邦鲫,Android系統(tǒng)有自己的垃圾回收機制,可以不定期的回收掉不使用的內(nèi)存空間神汹,當(dāng)然也包括Bitmap的空間庆捺。那為什么還需要這個方法呢?
Bitmap類的構(gòu)造方法都是私有的屁魏,所以開發(fā)者不能直接new出一個Bitmap對象滔以,只能通過BitmapFactory類的各種靜態(tài)方法來實例化一個Bitmap。仔細查看BitmapFactory的源代碼可以看到蚁堤,生成Bitmap對象最終都是通過JNI調(diào)用方式實現(xiàn)的醉者。所以,加載Bitmap到內(nèi)存里以后披诗,是包含兩部分內(nèi)存區(qū)域的撬即。簡單的說,一部分是Java部分的呈队,一部分是C部分的剥槐。這個Bitmap對象是由Java部分分配的,不用的時候系統(tǒng)就會自動回收了宪摧,但是那個對應(yīng)的C可用的內(nèi)存區(qū)域粒竖,虛擬機是不能直接回收的,這個只能調(diào)用底層的功能釋放几于。所以需要調(diào)用recycle()方法來釋放C部分的內(nèi)存蕊苗。從Bitmap類的源代碼也可以看到,recycle()方法里也的確是調(diào)用了JNI方法了的沿彭。
那如果不調(diào)用recycle()朽砰,是否就一定存在內(nèi)存泄露呢?也不是的。Android的每個應(yīng)用都運行在獨立的進程里瞧柔,有著獨立的內(nèi)存漆弄,如果整個進程被應(yīng)用本身或者系統(tǒng)殺死了,內(nèi)存也就都被釋放掉了造锅,當(dāng)然也包括C部分的內(nèi)存撼唾。
Android對于進程的管理是非常復(fù)雜的。簡單的說哥蔚,Android系統(tǒng)的進程分為幾個級別倒谷,系統(tǒng)會在內(nèi)存不足的情況下殺死一些低優(yōu)先級的進程,以提供給其它進程充足的內(nèi)存空間糙箍。在實際項目開發(fā)過程中恨锚,有的開發(fā)者會在退出程序的時候使用Process.killProcess(Process.myPid())的方式將自己的進程殺死,但是有的應(yīng)用僅僅會使用調(diào)用Activity.finish()方法的方式關(guān)閉掉所有的Activity倍靡。
在 2.3.3 及以下需要調(diào)用 recycle()函數(shù),在 2.3.3 以上 GC 會自動管理课舍,除非你明
確不需要再用塌西。
釋放Bitmap的示例代碼片段:
// 先判斷是否已經(jīng)回收
if(bitmap != null && !bitmap.isRecycled()){
// 回收并且置為null
bitmap.recycle();
bitmap = null;
}
System.gc();
從上面的代碼可以看到,bitmap.recycle()方法用于回收該Bitmap所占用的內(nèi)存筝尾,接著將bitmap置空捡需,最后使用System.gc()調(diào)用一下系統(tǒng)的垃圾回收器進行回收,可以通知垃圾回收器盡快進行回收筹淫。這里需要注意的是站辉,調(diào)用System.gc()并不能保證立即開始進行回收過程,而只是為了加快回收的到來损姜。
如何調(diào)用recycle()方法進行回收已經(jīng)了解了饰剥,那什么時候釋放Bitmap的內(nèi)存比較合適呢?一般來說摧阅,如果代碼已經(jīng)不再需要使用Bitmap對象了汰蓉,就可以釋放了。釋放內(nèi)存以后棒卷,就不能再使用該Bitmap對象了顾孽,如果再次使用,就會拋出異常比规。所以一定要保證不再使用的時候釋放若厚。比如,如果是在某個Activity中使用Bitmap蜒什,就可以在Activity的onStop()或者onDestroy()方法中進行回收测秸。
- 捕獲異常
為了避免應(yīng)用在分配Bitmap內(nèi)存的時候出現(xiàn)OutOfMemory異常以后Crash掉,需要特別注意實例化Bitmap部分的代碼。通常乞封,在實例化Bitmap的代碼中做裙,一定要對OutOfMemory異常進行捕獲.
Bitmap bitmap = null;
try {
// 實例化Bitmap
bitmap = BitmapFactory.decodeFile(path);
} catch (OutOfMemoryError e) {
//
}
if (bitmap == null) {
// 如果實例化失敗 返回默認的Bitmap對象
return defaultBitmapMap;
}
這里對初始化Bitmap對象過程中可能發(fā)生的OutOfMemory異常進行了捕獲。如果發(fā)生了OutOfMemory異常肃晚,應(yīng)用不會崩潰锚贱,而是得到了一個默認的Bitmap圖。
注意:很多開發(fā)者會習(xí)慣性的在代碼中直接捕獲Exception关串。但是對于OutOfMemoryError來說拧廊,這樣做是捕獲不到的。因為OutOfMemoryError是一種Error晋修,而不是Exception吧碾。在此僅僅做一下提醒,避免寫錯代碼而捕獲不到OutOfMemoryError墓卦。
- 緩存通用的Bitmap對象
有時候倦春,可能需要在一個Activity里多次用到同一張圖片。比如一個Activity會展示一些用戶的頭像列表落剪,而如果用戶沒有設(shè)置頭像的話睁本,則會顯示一個默認頭像,而這個頭像是位于應(yīng)用程序本身的資源文件中的忠怖。
如果有類似上面的場景呢堰,就可以對同一Bitmap進行緩存。如果不進行緩存凡泣,盡管看到的是同一張圖片文件枉疼,但是使用BitmapFactory類的方法來實例化出來的Bitmap,是不同的Bitmap對象鞋拟。緩存可以避免新建多個Bitmap對象骂维,避免內(nèi)存的浪費。
在Android應(yīng)用開發(fā)過程中贺纲,也會經(jīng)常使用緩存的技術(shù)席舍。這里所說的緩存有兩個級別,一個是硬盤緩存哮笆,一個是內(nèi)存緩存来颤。比如說,在開發(fā)網(wǎng)絡(luò)應(yīng)用過程中稠肘,可以將一些從網(wǎng)絡(luò)上獲取的數(shù)據(jù)保存到SD卡中福铅,下次直接從SD卡讀取,而不從網(wǎng)絡(luò)中讀取项阴,從而節(jié)省網(wǎng)絡(luò)流量滑黔。這種方式就是硬盤緩存笆包。再比如,應(yīng)用程序經(jīng)常會使用同一對象略荡,也可以放到內(nèi)存中緩存起來庵佣,需要的時候直接從內(nèi)存中讀取。這種方式就是內(nèi)存緩存汛兜。 - 壓縮圖片
如果圖片像素過大巴粪,使用BitmapFactory類的方法實例化Bitmap的過程中,需要大于8M的內(nèi)存空間粥谬,就必定會發(fā)生OutOfMemory異常肛根。這個時候該如何處理呢?如果有這種情況漏策,則可以將圖片縮小派哲,以減少載入圖片過程中的內(nèi)存的使用,避免異常發(fā)生掺喻。
使用BitmapFactory.Options設(shè)置inSampleSize就可以縮小圖片芭届。屬性值inSampleSize表示縮略圖大小為原始圖片大小的幾分之一。即如果這個值為2感耙,則取出的縮略圖的寬和高都是原始圖片的1/2喉脖,圖片的大小就為原始大小的1/4。
如果知道圖片的像素過大抑月,就可以對其進行縮小。那么如何才知道圖片過大呢舆蝴?
使用BitmapFactory.Options設(shè)置inJustDecodeBounds為true后谦絮,再使用decodeFile()等方法,并不會真正的分配空間洁仗,即解碼出來的Bitmap為null层皱,但是可計算出原始圖片的寬度和高度,即options.outWidth和options.outHeight赠潦。通過這兩個值叫胖,就可以知道圖片是否過大了。注意:如果程序的圖片的來源都是程序包中的資源她奥,或者是自己服務(wù)器上的圖片瓮增,圖片的大小是開發(fā)者可以調(diào)整的,那么一般來說哩俭,就只需要注意使用的圖片不要過大绷跑,并且注意代碼的質(zhì)量,及時回收Bitmap對象凡资,就能避免OutOfMemory異常的發(fā)生砸捏。
如果程序的圖片來自外界,這個時候就特別需要注意OutOfMemory的發(fā)生。一個是如果載入的圖片比較大垦藏,就需要先縮邪鹋;另一個是一定要捕獲異常掂骏,避免程序Crash轰驳。