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)建新的圖片垢油,指定起始坐標(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轰驳。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市芭挽,隨后出現(xiàn)的幾起案子滑废,更是在濱河造成了極大的恐慌,老刑警劉巖袜爪,帶你破解...
    沈念sama閱讀 219,366評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蠕趁,死亡現(xiàn)場離奇詭異,居然都是意外死亡辛馆,警方通過查閱死者的電腦和手機俺陋,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,521評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來昙篙,“玉大人腊状,你說我怎么就攤上這事√桑” “怎么了缴挖?”我有些...
    開封第一講書人閱讀 165,689評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長焚辅。 經(jīng)常有香客問我映屋,道長,這世上最難降的妖魔是什么同蜻? 我笑而不...
    開封第一講書人閱讀 58,925評論 1 295
  • 正文 為了忘掉前任棚点,我火速辦了婚禮,結(jié)果婚禮上湾蔓,老公的妹妹穿的比我還像新娘瘫析。我一直安慰自己,他們只是感情好默责,可當(dāng)我...
    茶點故事閱讀 67,942評論 6 392
  • 文/花漫 我一把揭開白布贬循。 她就那樣靜靜地躺著,像睡著了一般桃序。 火紅的嫁衣襯著肌膚如雪甘有。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,727評論 1 305
  • 那天葡缰,我揣著相機與錄音亏掀,去河邊找鬼忱反。 笑死,一個胖子當(dāng)著我的面吹牛滤愕,可吹牛的內(nèi)容都是我干的温算。 我是一名探鬼主播,決...
    沈念sama閱讀 40,447評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼间影,長吁一口氣:“原來是場噩夢啊……” “哼注竿!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起魂贬,我...
    開封第一講書人閱讀 39,349評論 0 276
  • 序言:老撾萬榮一對情侶失蹤巩割,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后付燥,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體宣谈,經(jīng)...
    沈念sama閱讀 45,820評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,990評論 3 337
  • 正文 我和宋清朗相戀三年键科,在試婚紗的時候發(fā)現(xiàn)自己被綠了闻丑。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,127評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡勋颖,死狀恐怖嗦嗡,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情饭玲,我是刑警寧澤侥祭,帶...
    沈念sama閱讀 35,812評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站茄厘,受9級特大地震影響矮冬,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜蚕断,卻給世界環(huán)境...
    茶點故事閱讀 41,471評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望入挣。 院中可真熱鬧亿乳,春花似錦、人聲如沸径筏。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,017評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽滋恬。三九已至聊训,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間恢氯,已是汗流浹背带斑。 一陣腳步聲響...
    開封第一講書人閱讀 33,142評論 1 272
  • 我被黑心中介騙來泰國打工鼓寺, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人勋磕。 一個月前我還...
    沈念sama閱讀 48,388評論 3 373
  • 正文 我出身青樓妈候,卻偏偏與公主長得像,于是被迫代替她去往敵國和親挂滓。 傳聞我的和親對象是個殘疾皇子苦银,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,066評論 2 355

推薦閱讀更多精彩內(nèi)容