Bitmap-詳解

參考資料


目錄

    1. Bitmap
    1. BitmapFactory
    1. Bitmap加載方法
    1. Bitmap | Drawable | InputStream | Byte[ ] 之間轉(zhuǎn)換
    1. Bitmap常用操作
    1. 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)建新的圖片,指定起始坐標以及新圖像的高寬

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 用于目標位圖的像素壓縮比(要生成的位圖)
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。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容