摘要:上面的代碼沒用過因為我是固定來取樣的數據,為什么這個壓縮方法叫采樣率壓縮是因為配合,先獲取圖片的寬高這個過程就是取樣。
目錄介紹
01.如何計算Bitmap占用內存
1.1 如何計算占用內存
1.2 上面方法計算內存對嗎
1.3 一個像素占用多大內存
02.Bitmap常見四種顏色格式
2.1 什么是bitmap
2.2 Android常見是那種
2.3 常見四種顏色格式介紹
2.4 Bitmap到底有幾種顏色格式
03.Bitmap壓縮技術
3.1 質量壓縮
3.2 采樣率壓縮
3.3 縮放法壓縮
04.Bitmap回收問題
4.1 recycle()方法
4.2 緩存原理
4.3 Bitmap的復用
05.Bitmap常見操作
5.1 Bitmap的壓縮方式
5.2 Bitmap如何復用
5.3 Bitmap使用API獲取內存
5.4 該博客對應測試項目地址
好消息博客筆記大匯總【16年3月到至今】,包括Java基礎及深入知識點,Android技術博客,Python學習筆記等等,還包括平時開發中遇到的bug匯總,當然也在工作之余收集了大量的面試題,長期更新維護并且修正,持續完善……開源的文件是markdown格式的!同時也開源了生活博客,從12年起,積累共計50篇[近30萬字],轉載請注明出處,謝謝!
鏈接地址:https://github.com/yangchong2...
如果覺得好,可以star一下,謝謝!當然也歡迎提出建議,萬事起于忽微,量變引起質變!
輪播圖封裝庫:https://github.com/yangchong2...
輕量級版本更新彈窗:https://github.com/yangchong2...
通知欄封裝庫:https://github.com/yangchong2...
01.如何計算Bitmap占用內存歡迎直接查看demo的壓縮效果,https://github.com/yangchong2...
1.1 如何計算占用內存如果圖片要顯示下Android設備上,ImageView最終是要加載Bitmap對象的,就要考慮單個Bitmap對象的內存占用了,如何計算一張圖片的加載到內存的占用呢?其實就是所有像素的內存占用總和:
bitmap內存大小 = 圖片長度 x 圖片寬度 x 單位像素占用的字節數
起決定因素就是最后那個參數了,Bitmap"常見有2種編碼方式:ARGB_8888和RGB_565,ARGB_8888每個像素點4個byte,RGB_565是2個byte,一般都采用ARGB_8888這種。那么常見的1080*1920的圖片內存占用就是:1920 x 1080 x 4 = 7.9M
1.2 上面方法計算內存對嗎
我看到好多博客都是這樣計算的,但是這樣算對嗎?有沒有哥們試驗過這種方法正確性?我覺得看博客要對博主表示懷疑,論證別人寫的是否正確。更多詳細可以看我的GitHub:https://github.com/yangchong211
說出我的結論:上面1.1這種說法也對,但是不全對,沒有說明場景,同時也忽略了一個影響項:Density。接下來看看源代碼。
inDensity默認為圖片所在文件夾對應的密度;inTargetDensity為當前系統密度。
加載一張本地資源圖片,那么它占用的內存 = width height nTargetDensity/inDensity nTargetDensity/inDensity 一個像素所占的內存。
@Nullable public static Bitmap decodeResourceStream(@Nullable Resources res, @Nullable TypedValue value, @Nullable InputStream is, @Nullable Rect pad, @Nullable Options opts) { validate(opts); if (opts == null) { opts = new Options(); } if (opts.inDensity == 0 && value != null) { final int density = value.density; if (density == TypedValue.DENSITY_DEFAULT) { opts.inDensity = DisplayMetrics.DENSITY_DEFAULT; } else if (density != TypedValue.DENSITY_NONE) { opts.inDensity = density; } } if (opts.inTargetDensity == 0 && res != null) { opts.inTargetDensity = res.getDisplayMetrics().densityDpi; } return decodeStream(is, pad, opts); }
正確說法,這個注意呢?計算公式如下所示
對資源文件:width height nTargetDensity/inDensity nTargetDensity/inDensity 一個像素所占的內存;
別的:width height 一個像素所占的內存;
1.3 一個像素占用多大內存
Bitmap.Config用來描述圖片的像素是怎么被存儲的?
ARGB_8888: 每個像素4字節. 共32位,默認設置。
Alpha_8: 只保存透明度,共8位,1字節。
ARGB_4444: 共16位,2字節。
RGB_565:共16位,2字節,只存儲RGB值。
02.Bitmap常見四種顏色格式 2.1 什么是bitmap位圖文件(Bitmap),擴展名可以是.bmp或者.dib。位圖是Windows標準格式圖形文件,它將圖像定義為由點(像素)組成,每個點可以由多種色彩表示,包括2、4、8、16、24和32位色彩。位圖文件是非壓縮格式的,需要占用較大存儲空間。
2.2 Android常見是那種
在Gesture類中
在Notification類中
在fw源碼中bitmap圖片一般是以ARGB_8888(ARGB分別代表的是透明度,紅色,綠色,藍色,每個值分別用8bit來記錄,也就是一個像素會占用4byte,共32bit)來進行存儲的。
2.3 常見四種顏色格式介紹
四種顏色格式如下所示
說明
在實際應用中而言,建議使用ARGB_8888以及RGB_565。 如果你不需要透明度,選擇RGB_565,可以減少一半的內存占用。
ARGB_8888:ARGB分別代表的是透明度,紅色,綠色,藍色,每個值分別用8bit來記錄,也就是一個像素會占用4byte,共32bit.
ARGB_4444:ARGB的是每個值分別用4bit來記錄,一個像素會占用2byte,共16bit.
RGB_565:R=5bit,G=6bit,B=5bit,不存在透明度,每個像素會占用2byte,共16bit
ALPHA_8:該像素只保存透明度,會占用1byte,共8bit.
2.4 Bitmap到底有幾種顏色格式
上面我說到了常見的四種,言下之意應該不止四種,那到底有幾種呢?查看源碼可知,具體有6種類型。查看Bitmap源碼之Config配置。
配置Config.HARDWARE為啥異常,看下面源碼提示
03.Bitmap壓縮技術 3.1 質量壓縮
質量壓縮方法:在保持像素的前提下改變圖片的位深及透明度等,來達到壓縮圖片的目的,這樣適合去傳遞二進制的圖片數據,比如分享圖片,要傳入二進制數據過去,限制500kb之內。
1、bitmap圖片的大小不會改變
2、bytes.length是隨著quality變小而變小的。
/** * 第一種:質量壓縮法 * @param image 目標原圖 * @param maxSize 最大的圖片大小 * @return bitmap,注意可以測試以下壓縮前后bitmap的大小值 */ public static Bitmap compressImage(Bitmap image , long maxSize) { int byteCount = image.getByteCount(); Log.i("yc壓縮圖片","壓縮前大小"+byteCount); ByteArrayOutputStream baos = new ByteArrayOutputStream(); // 把ByteArrayInputStream數據生成圖片 Bitmap bitmap = null; // 質量壓縮方法,options的值是0-100,這里100表示原來圖片的質量,不壓縮,把壓縮后的數據存放到baos中 image.compress(Bitmap.CompressFormat.JPEG, 100, baos); int options = 90; // 循環判斷如果壓縮后圖片是否大于maxSize,大于繼續壓縮 while (baos.toByteArray().length > maxSize) { // 重置baos即清空baos baos.reset(); // 這里壓縮options%,把壓縮后的數據存放到baos中 image.compress(Bitmap.CompressFormat.JPEG, options, baos); // 每次都減少10,當為1的時候停止,options<10的時候,遞減1 if(options == 1){ break; }else if (options <= 10) { options -= 1; } else { options -= 10; } } byte[] bytes = baos.toByteArray(); if (bytes.length != 0) { // 把壓縮后的數據baos存放到bytes中 bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length); int byteCount1 = bitmap.getByteCount(); Log.i("yc壓縮圖片","壓縮后大小"+byteCount1); } return bitmap; } /** * 第一種:質量壓縮法 * * @param src 源圖片 * @param maxByteSize 允許最大值字節數 * @param recycle 是否回收 * @return 質量壓縮壓縮過的圖片 */ public static Bitmap compressByQuality(final Bitmap src, final long maxByteSize, final boolean recycle) { if (src == null || src.getWidth() == 0 || src.getHeight() == 0 || maxByteSize <= 0) { return null; } Log.i("yc壓縮圖片","壓縮前大小"+src.getByteCount()); ByteArrayOutputStream baos = new ByteArrayOutputStream(); src.compress(Bitmap.CompressFormat.JPEG, 100, baos); byte[] bytes; if (baos.size() <= maxByteSize) {// 最好質量的不大于最大字節,則返回最佳質量 bytes = baos.toByteArray(); } else { baos.reset(); src.compress(Bitmap.CompressFormat.JPEG, 0, baos); if (baos.size() >= maxByteSize) { // 最差質量不小于最大字節,則返回最差質量 bytes = baos.toByteArray(); } else { // 二分法尋找最佳質量 int st = 0; int end = 100; int mid = 0; while (st < end) { mid = (st + end) / 2; baos.reset(); src.compress(Bitmap.CompressFormat.JPEG, mid, baos); int len = baos.size(); if (len == maxByteSize) { break; } else if (len > maxByteSize) { end = mid - 1; } else { st = mid + 1; } } if (end == mid - 1) { baos.reset(); src.compress(Bitmap.CompressFormat.JPEG, st, baos); } bytes = baos.toByteArray(); } } if (recycle && !src.isRecycled()){ src.recycle(); } Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length); Log.i("yc壓縮圖片","壓縮后大小"+bitmap.getByteCount()); return bitmap; } /** * 第一種:質量壓縮法 * * @param src 源圖片 * @param quality 質量 * @param recycle 是否回收 * @return 質量壓縮后的圖片 */ public static Bitmap compressByQuality(final Bitmap src, @IntRange(from = 0, to = 100) final int quality, final boolean recycle) { if (src == null || src.getWidth() == 0 || src.getHeight() == 0) { return null; } Log.i("yc壓縮圖片","壓縮前大小"+src.getByteCount()); ByteArrayOutputStream baos = new ByteArrayOutputStream(); src.compress(Bitmap.CompressFormat.JPEG, quality, baos); byte[] bytes = baos.toByteArray(); if (recycle && !src.isRecycled()) { src.recycle(); } Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length); Log.i("yc壓縮圖片","壓縮后大小"+bitmap.getByteCount()); return bitmap; }3.2 采樣率壓縮
什么是采樣率壓縮?
設置inSampleSize的值(int類型)后,假如設為n,則寬和高都為原來的1/n,寬高都減少,內存降低。上面的代碼沒用過options.inJustDecodeBounds = true;因為我是固定來取樣的數據,為什么這個壓縮方法叫采樣率壓縮?是因為配合inJustDecodeBounds,先獲取圖片的寬、高(這個過程就是取樣)。然后通過獲取的寬高,動態的設置inSampleSize的值。當inJustDecodeBounds設置為true的時候, BitmapFactory通過decodeResource或者decodeFile解碼圖片時,將會返回空(null)的Bitmap對象,這樣可以避免Bitmap的內存分配, 但是它可以返回Bitmap的寬度、高度以及MimeType。
/** * 第二種:按采樣大小壓縮 * * @param src 源圖片 * @param sampleSize 采樣率大小 * @param recycle 是否回收 * @return 按采樣率壓縮后的圖片 */ public static Bitmap compressBySampleSize(final Bitmap src, final int sampleSize, final boolean recycle) { if (src == null || src.getWidth() == 0 || src.getHeight() == 0) { return null; } Log.i("yc壓縮圖片","壓縮前大小"+src.getByteCount()); BitmapFactory.Options options = new BitmapFactory.Options(); options.inSampleSize = sampleSize; ByteArrayOutputStream baos = new ByteArrayOutputStream(); src.compress(Bitmap.CompressFormat.JPEG, 100, baos); byte[] bytes = baos.toByteArray(); if (recycle && !src.isRecycled()) { src.recycle(); } Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length, options); Log.i("yc壓縮圖片","壓縮后大小"+bitmap.getByteCount()); return bitmap; } /** * 第二種:按采樣大小壓縮 * * @param src 源圖片 * @param maxWidth 最大寬度 * @param maxHeight 最大高度 * @param recycle 是否回收 * @return 按采樣率壓縮后的圖片 */ public static Bitmap compressBySampleSize(final Bitmap src, final int maxWidth, final int maxHeight, final boolean recycle) { if (src == null || src.getWidth() == 0 || src.getHeight() == 0) { return null; } Log.i("yc壓縮圖片","壓縮前大小"+src.getByteCount()); BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; ByteArrayOutputStream baos = new ByteArrayOutputStream(); src.compress(Bitmap.CompressFormat.JPEG, 100, baos); byte[] bytes = baos.toByteArray(); BitmapFactory.decodeByteArray(bytes, 0, bytes.length, options); options.inSampleSize = calculateInSampleSize(options, maxWidth, maxHeight); options.inJustDecodeBounds = false; if (recycle && !src.isRecycled()) { src.recycle(); } Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length, options); Log.i("yc壓縮圖片","壓縮后大小"+bitmap.getByteCount()); return bitmap; } /** * 計算獲取縮放比例inSampleSize */ private static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) { final int height = options.outHeight; final int width = options.outWidth; int inSampleSize = 1; if (height > reqHeight || width > reqWidth) { final int heightRatio = Math.round((float) height / (float) reqHeight); final int widthRatio = Math.round((float) width / (float) reqWidth); inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio; } final float totalPixels = width * height; final float totalReqPixelsCap = reqWidth * reqHeight * 2; while (totalPixels / (inSampleSize * inSampleSize) > totalReqPixelsCap) { inSampleSize++; } return inSampleSize; }3.3 縮放法壓縮
Android中使用Matrix對圖像進行縮放、旋轉、平移、斜切等變換的。
Matrix提供了一些方法來控制圖片變換:Matrix調用一系列set,pre,post方法時,可視為將這些方法插入到一個隊列。當然,按照隊列中從頭至尾的順序調用執行。其中pre表示在隊頭插入一個方法,post表示在隊尾插入一個方法。而set表示把當前隊列清空,并且總是位于隊列的最中間位置。當執行了一次set后:pre方法總是插入到set前部的隊列的最前面,post方法總是插入到set后部的隊列的最后面
setTranslate(float dx,float dy):控制Matrix進行位移。 setSkew(float kx,float ky):控制Matrix進行傾斜,kx、ky為X、Y方向上的比例。 setSkew(float kx,float ky,float px,float py):控制Matrix以px、py為軸心進行傾斜,kx、ky為X、Y方向上的傾斜比例。 setRotate(float degrees):控制Matrix進行depress角度的旋轉,軸心為(0,0)。 setRotate(float degrees,float px,float py):控制Matrix進行depress角度的旋轉,軸心為(px,py)。 setScale(float sx,float sy):設置Matrix進行縮放,sx、sy為X、Y方向上的縮放比例。 setScale(float sx,float sy,float px,float py):設置Matrix以(px,py)為軸心進行縮放,sx、sy為X、Y方向上的縮放比例。
縮放法壓縮工具類代碼
/** * 第三種:按縮放壓縮 * * @param src 源圖片 * @param newWidth 新寬度 * @param newHeight 新高度 * @param recycle 是否回收 * @return 縮放壓縮后的圖片 */ public static Bitmap compressByScale(final Bitmap src, final int newWidth, final int newHeight, final boolean recycle) { return scale(src, newWidth, newHeight, recycle); } public static Bitmap compressByScale(final Bitmap src, final float scaleWidth, final float scaleHeight, final boolean recycle) { return scale(src, scaleWidth, scaleHeight, recycle); } /** * 縮放圖片 * * @param src 源圖片 * @param scaleWidth 縮放寬度倍數 * @param scaleHeight 縮放高度倍數 * @param recycle 是否回收 * @return 縮放后的圖片 */ private static Bitmap scale(final Bitmap src, final float scaleWidth, final float scaleHeight, final boolean recycle) { if (src == null || src.getWidth() == 0 || src.getHeight() == 0) { return null; } Matrix matrix = new Matrix(); matrix.setScale(scaleWidth, scaleHeight); Bitmap ret = Bitmap.createBitmap(src, 0, 0, src.getWidth(), src.getHeight(), matrix, true); if (recycle && !src.isRecycled()) { src.recycle(); } return ret; }04.Bitmap回收問題 4.1 recycle()方法
如何調用這個recycle()方法
if (bitmap != null && !bitmap.isRecycled()) { bitmap.recycle(); bitmap = null; }
思考以下,為何調用recycle()需要做非空判斷?這里可以引出bitmap系統回收功能。小楊我如果分析不對,歡迎反饋。
首先看看源碼……順便翻一下該方法的注釋!我是用有道翻譯的,大意如下:釋放與此位圖關聯的本機對象,并清除對像素數據的引用。這將不會同步釋放像素數據;如果沒有其他引用,它只允許垃圾收集。位圖被標記為“死”,這意味著如果調用getPixels()或setPixels(),它將拋出異常,并且不會繪制任何東西。此操作不能反轉,因此只有在確定沒有進一步使用位圖的情況下才應調用該操作。這是一個高級調用,通常不需要調用,因為當沒有對此位圖的引用時,普通GC進程將釋放此內存。
public void recycle() { if (!mRecycled && mNativePtr != 0) { if (nativeRecycle(mNativePtr)) { // return value indicates whether native pixel object was actually recycled. // false indicates that it is still in use at the native level and these // objects should not be collected now. They will be collected later when the // Bitmap itself is collected. mNinePatchChunk = null; } mRecycled = true; } }
通常不需要調用?這是為啥?
在Android3.0以后Bitmap是存放在堆中的,只要回收堆內存即可。官方建議我們3.0以后使用recycle()方法進行回收,該方法可以不主動調用,因為垃圾回收器會自動收集不可用的Bitmap對象進行回收。
那么何是進行回收呢?這里面涉及到bitmap的緩存算法,還有GC回收垃圾機制。關于GC回收機制可以看我這篇博客:https://blog.csdn.net/m0_3770...
大概就是移除最少使用的緩存和使用最久的緩存,先說出結論,下來接著分析!
4.2 緩存原理
LruCache原理
LruCache是個泛型類,內部采用LinkedHashMap來實現緩存機制,它提供get方法和put方法來獲取緩存和添加緩存,其最重要的方法trimToSize是用來移除最少使用的緩存和使用最久的緩存,并添加最新的緩存到隊列中。
4.3 Bitmap的復用
Android3.0之后,并沒有強調Bitmap.recycle();而是強調Bitmap的復用。
使用LruCache對Bitmap進行緩存,當再次使用到這個Bitmap的時候直接獲取,而不用重走編碼流程。
Android3.0(API 11之后)引入了BitmapFactory.Options.inBitmap字段,設置此字段之后解碼方法會嘗試復用一張存在的Bitmap。這意味著Bitmap的內存被復用,避免了內存的回收及申請過程,顯然性能表現更佳。
使用這個字段有幾點限制:
聲明可被復用的Bitmap必須設置inMutable為true;
Android4.4(API 19)之前只有格式為jpg、png,同等寬高(要求苛刻),inSampleSize為1的Bitmap才可以復用;
Android4.4(API 19)之前被復用的Bitmap的inPreferredConfig會覆蓋待分配內存的Bitmap設置的inPreferredConfig;
Android4.4(API 19)之后被復用的Bitmap的內存必須大于需要申請內存的Bitmap的內存;
Android4.4(API 19)之前待加載Bitmap的Options.inSampleSize必須明確指定為1。
05.Bitmap常見操作 5.1 Bitmap的壓縮方式
常見壓縮方法Api
Bitmap.compress(),質量壓縮,不會對內存產生影響;
BitmapFactory.Options.inSampleSize,內存壓縮;
Bitmap.compress()
質量壓縮,不會對內存產生影響
它是在保持像素的前提下改變圖片的位深及透明度等,來達到壓縮圖片的目的,不會減少圖片的像素。進過它壓縮的圖片文件大小會變小,但是解碼成bitmap后占得內存是不變的。
BitmapFactory.Options.inSampleSize
內存壓縮
解碼圖片時,設置BitmapFactory.Options類的inJustDecodeBounds屬性為true,可以在Bitmap不被加載到內存的前提下,獲取Bitmap的原始寬高。而設置BitmapFactory.Options的inSampleSize屬性可以真實的壓縮Bitmap占用的內存,加載更小內存的Bitmap。
設置inSampleSize之后,Bitmap的寬、高都會縮小inSampleSize倍。例如:一張寬高為2048x1536的圖片,設置inSampleSize為4之后,實際加載到內存中的圖片寬高是512x384。占有的內存就是0.75M而不是12M,足足節省了15倍。
備注:inSampleSize值的大小不是隨便設、或者越大越好,需要根據實際情況來設置。inSampleSize比1小的話會被當做1,任何inSampleSize的值會被取接近2的冪值。
5.2 Bitmap如何復用
Bitmap復用的實驗,代碼如下所示,然后看打印的日志信息
從內存地址的打印可以看出,兩個對象其實是一個對象,Bitmap復用成功;
bitmapReuse占用的內存(4346880)正好是bitmap占用內存(1228800)的四分之一;
getByteCount()獲取到的是當前圖片應當所占內存大小,getAllocationByteCount()獲取到的是被復用Bitmap真實占用內存大小。雖然bitmapReuse的內存只有4346880,但是因為是復用的bitmap的內存,因而其真實占用的內存大小是被復用的bitmap的內存大小(1228800)。這也是getAllocationByteCount()可能比getByteCount()大的原因。
@RequiresApi(api = Build.VERSION_CODES.KITKAT) private void initBitmap() { BitmapFactory.Options options = new BitmapFactory.Options(); // 圖片復用,這個屬性必須設置; options.inMutable = true; // 手動設置縮放比例,使其取整數,方便計算、觀察數據; options.inDensity = 320; options.inTargetDensity = 320; Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.bg_autumn_tree_min, options); // 對象內存地址; Log.i("ycBitmap", "bitmap = " + bitmap); Log.i("ycBitmap", "ByteCount = " + bitmap.getByteCount() + ":::bitmap:AllocationByteCount = " + bitmap.getAllocationByteCount()); // 使用inBitmap屬性,這個屬性必須設置; options.inBitmap = bitmap; options.inDensity = 320; // 設置縮放寬高為原始寬高一半; options.inTargetDensity = 160; options.inMutable = true; Bitmap bitmapReuse = BitmapFactory.decodeResource(getResources(), R.drawable.bg_kites_min, options); // 復用對象的內存地址; Log.i("ycBitmap", "bitmapReuse = " + bitmapReuse); Log.i("ycBitmap", "bitmap:ByteCount = " + bitmap.getByteCount() + ":::bitmap:AllocationByteCount = " + bitmap.getAllocationByteCount()); Log.i("ycBitmap", "bitmapReuse:ByteCount = " + bitmapReuse.getByteCount() + ":::bitmapReuse:AllocationByteCount = " + bitmapReuse.getAllocationByteCount()); //11-26 18:24:07.971 15470-15470/com.yc.cn.ycbanner I/ycBitmap: bitmap = android.graphics.Bitmap@9739bff //11-26 18:24:07.972 15470-15470/com.yc.cn.ycbanner I/ycBitmap: bitmap:ByteCount = 4346880:::bitmap:AllocationByteCount = 4346880 //11-26 18:24:07.994 15470-15470/com.yc.cn.ycbanner I/ycBitmap: bitmapReuse = android.graphics.Bitmap@9739bff //11-26 18:24:07.994 15470-15470/com.yc.cn.ycbanner I/ycBitmap: bitmap:ByteCount = 1228800:::bitmap:AllocationByteCount = 4346880 //11-26 18:24:07.994 15470-15470/com.yc.cn.ycbanner I/ycBitmap: bitmapReuse:ByteCount = 1228800:::bitmapReuse:AllocationByteCount = 4346880 }5.3 Bitmap使用API獲取內存
getByteCount()
getByteCount()方法是在API12加入的,代表存儲Bitmap的色素需要的最少內存。API19開始getAllocationByteCount()方法代替了getByteCount()。
getAllocationByteCount()
API19之后,Bitmap加了一個Api:getAllocationByteCount();代表在內存中為Bitmap分配的內存大小。
public final int getAllocationByteCount() { if (mRecycled) { Log.w(TAG, "Called getAllocationByteCount() on a recycle()"d bitmap! " + "This is undefined behavior!"); return 0; } return nativeGetAllocationByteCount(mNativePtr); }
思考: getByteCount()與getAllocationByteCount()的區別?
一般情況下兩者是相等的;
通過復用Bitmap來解碼圖片,如果被復用的Bitmap的內存比待分配內存的Bitmap大,那么getByteCount()表示新解碼圖片占用內存的大小(并非實際內存大小,實際大小是復用的那個Bitmap的大小),getAllocationByteCount()表示被復用Bitmap真實占用的內存大小(即mBuffer的長度)。
在復用Bitmap的情況下,getAllocationByteCount()可能會比getByteCount()大。
5.4 該博客對應測試項目地址歡迎直接查看demo的壓縮效果,https://github.com/yangchong2...
關于其他內容介紹 01.關于博客匯總鏈接1.技術博客匯總
2.開源項目匯總
3.生活博客匯總
4.喜馬拉雅音頻匯總
5.其他匯總
02.關于我的博客我的個人站點:www.yczbj.org,www.ycbjie.cn
github:https://github.com/yangchong211
知乎:https://www.zhihu.com/people/...
簡書:http://www.jianshu.com/u/b7b2...
csdn:http://my.csdn.net/m0_37700275
喜馬拉雅聽書:http://www.ximalaya.com/zhubo...
開源中國:https://my.oschina.net/zbj161...
泡在網上的日子:http://www.jcodecraeer.com/me...
郵箱:yangchong211@163.com
阿里云博客:https://yq.aliyun.com/users/a... 239.headeruserinfo.3.dT4bcV
segmentfault頭條:https://segmentfault.com/u/xi...
掘金:https://juejin.im/user/593943...
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/72445.html
摘要:對于同一層級的一組子節點,它們可以通過唯一進行區分。基于以上三個前提策略,分別對以及進行算法優化。鏈表的每一個節點是,而不是在之前的虛擬節點。是當前層的第一個節點。再次提醒,是的一層。 文章首發于個人博客 這是我 Deep In React 系列的第二篇文章,如果還沒有讀過的強烈建議你先讀第一篇:詳談 React Fiber 架構(1)。 前言 我相信在看這篇文章的讀者一般都已經了解...
閱讀 1906·2021-11-22 14:44
閱讀 1672·2021-11-02 14:46
閱讀 3657·2021-10-13 09:40
閱讀 2601·2021-09-07 09:58
閱讀 1586·2021-09-03 10:28
閱讀 1658·2019-08-29 15:30
閱讀 976·2019-08-29 15:28
閱讀 1469·2019-08-26 12:20