android日志收集工具,Android Bitmap史上最詳細全解 | 原力計劃

 2023-10-22 阅读 22 评论 0

摘要:作者 | ? IF ?責編 | 王曉曼出品 | CSDN博客Bitmap的相關使用?關于 Bitmap ,之前以為它和 Drawable 差不多,就是一種圖片,直到淚水打濕了我胸前的紅領巾,我決定整理一波關于 Bitmap 的姿勢!Bitmap相關的使用主要有兩種:1.給 ImageView 設

作者 | ? IF ?

責編 | 王曉曼

出品 | CSDN博客

Bitmap的相關使用

?

關于 Bitmap ,之前以為它和 Drawable 差不多,就是一種圖片,直到淚水打濕了我胸前的紅領巾,我決定整理一波關于 Bitmap 的姿勢!

Bitmap相關的使用主要有兩種:

1.給 ImageView 設置背景;

2.當做畫布來使用 。

android日志收集工具。分別對應下面兩個方法:

?imageView.setImageBitmap(Bitmap?bm);Canvas?canvas?=?new?Canvas(Bitmap?bm)?

Bitmap的格式

我們知道 Bitmap 是位圖,是由像素點組成的,這就涉及到兩個問題:

第一:如何存儲每個像素點?

第二:怎么壓縮像素點?

1、存儲格式

Bitmap有四種存儲方式,對應Bitmap.Config中的四個常量:

  • android recyclerview緩存機制?ALPHA_8:只存儲透明度,不存儲色值,1個像素點占1個字節;

  • ARGB_4444:ARGB各用4位存儲,1個像素點16位占2個字節;

  • ARGB_8888:ARGB各用8位存儲,1個像素點32位占4個字節;

  • RGB_565:只存儲色值,不存儲透明度,默認不透明,RGB分別占5,6,5位,一個像素點占用16位2個字節。

一般情況下,我們不會使用 ALPHA_8 ,他只存儲透明度,沒啥用處。對于 ARGB_4444 ,它的畫質又太感人了,ARGB_8888 畫質高但是占內存, RGB_565 還行,就是不可以設置透明度。

注意以下三點即可:

  • android內存分析工具。一般情況下用ARGB_8888格式存儲Bitmap;

  • ARGB_4444畫面慘不忍睹,被棄用;

  • 假如對圖片沒有透明度要求,可以使用RGB_565,比ARGB_8888節省一半的內存開銷。

2、壓縮格式

我們不妨來計算一下,如果一張和手機屏幕大小一樣的Bitmap圖片,采用ARGB_8888格式存儲需要多大的內存!

按照1024*768的屏幕大小來計算,每個像素需要32位也就是4個字節:

result?=?1024*768*32B=25165824B=24MB

android leakcanary原理、一張手機屏幕大小的 Bitmap 圖片竟然要 24M ? 那就不奇怪我的 APP 為什么一直閃退了,只不過用 for 循環創 建了幾十個用在滑動列表里面。

所以我們必須要對圖片進行壓縮呀,壓縮格式使用枚舉類 Bitmap.CompressFormat 中,有以下三種:

  • Bitmap.CompressFormat.JPEG :采用 JPEG 壓縮算法,是一種有損壓縮格式,會在壓縮過程中改變圖像原本質量,畫質越差,對原來的圖片質量損傷越大,但是得到的文件比較小,而且 JPEG 不支持透明度,當遇到透明度像素時,會以黑色背景填充。

  • Bitmap.CompressFormat.PNG :采用 PNG 算法,是一種支持透明度的無損壓縮格式。

  • Bitmap.CompressFormat.WEBP : WEBP 是一種同時提供了有損壓縮和無損壓縮的圖片文件格式,在14<=api<=17時,WEBP 是一種有損壓縮格式,而且不支持透明度,在 api18 以后 WEBP 是一種無損壓縮格式,而且支持透明度,有損壓縮時,在質量相同的情況下, WEBP 格式的圖片體積比 JPEG 小40%,但是編碼時間比 JPEG 長8倍。在無損壓縮時,無損的 WEBP 圖片比 PNG 壓縮小26%,但是 WEBP 的壓縮時間是 PNG 格式壓縮時間的5倍。

?

Bitmap創建方法

android fragment生命周期。1、Bitmap.Options

想要創建一個Bitmap有很多種方法,其中很多方法都要求傳入一個Bitmap.Options,它是什么呢,有什么作用呢?

這個參數的作用非常大,他可以設置 Bitmap 的采樣率,通過改變圖片的寬度高度和縮放比例等,以達到減少圖片像素數的目的,一言以蔽之,通過設置這個參數我們可以很好的控制顯示和使用 Bitmap 。實際開發過程中,可以靈活設置該值,以降低 OOM 發生的概率。

介紹幾個重要的成員變量:

  • inJustDecodeBounds:boolean類型,設為true時,無需要把圖片加載入內存就可以獲取圖片的高度,寬度和圖片的MIME類型。

高度通過options.outWidth獲取 寬度通過options.outHeight獲取;

Androidhelper官方文檔?MIME通過options.outMineType獲取。

  • inSampleSize:這個字段表示采樣率,打個比方說,設置為4,則是從原本圖片的四個像素中取一個像素作為結果返回。其余的都被丟棄。可見,采樣率越大,圖片越小,失真越嚴重。如何計算采樣率呢?看一下這段代碼你就會明白:

?public?int?getSampleSize(BitmapFactory.Options?options?,?int?dstWidth,int?dstHeight){//dstWidth:表示目前ImageView的寬度//dstHeight:表示目標ImageView的高度//option中獲取bitmap圖片的信息int??rawWidth?=?options.outWidth;int??rawHeight?=?options.outHeight;int?sampleSize=1;if(rawWidth>dstWidth||rawHeight>dstHeight){float?ratioHeight?=?(float)?(rawHeight/dstHeight);float?ratioWidth?=?(float)?(rawWidth/dstWidth);sampleSize?=?(int)?Math.min(rawHeight,?ratioWidth);}return?sampleSize;}

為了更清楚的介紹下面的知識,先補充幾點:

  • 不同名稱的資源文件夾是為了適配不同的屏幕分辨率的,當屏幕分辨率與文件所在資源文件夾對應的分辨率相等時,直接使用圖片,不需要進行放縮。

  • 當屏幕分辨率與圖片所在文件夾所對應的分辨率不同時,會進行縮放,縮放比例是屏幕分辨率/文件夾所對應的分辨率。

  • 從本地文件中加載圖片時,不會對圖片進行縮放噢。

安卓數據持久化,inScald :這個參數表示,在可以縮放時,是否對當前文件進行放縮,如果設置為 false 就不放縮。設置為 true,則會根據文件夾分辨率和屏幕分辨率進行動態縮放。

inPreferredConfig :這個參數是用來設置像素的存儲格式的。

關于 Options 就介紹這幾個關鍵的字段,下面進入重頭戲,創建Bitmap。

2、BitmapFactory

BitmapFactory 提供了多種創建 bitmap 的靜態方法:

//從資源文件中通過id加載bitmap
//Resources?res:資源文件,可以context.getResources()獲得
//id:資源文件的id,如R.drawable.xxx
public?static?Bitmap?decodeResources(Resources?res,int?id)
//第二種只是第一種的重載方法,多了個Options參數
public?static?Bitmap?decodeResources(Resources?res,int?id,Options?opt)
//傳入文件路徑加載,比如加載sd卡中的文件
//pathName:文件的全路徑名
public?static?Bitmap?decodeFile(String?pathName);
public?static?Bitmap?decodeFile(String?pathName,Options?opt);
//從byte數組中加載
//offset:對應data數組的起始下標
//length:截取的data數組的長度
public?static?Bitmap?decodeByteArray(byte[]?data,int?offset?,?int?length);
public?static?Bitmap?decodeByteArray(byte[]?data,int?offset?,?int?length,Options?opt);
//從輸入流中加載圖片
//InputStream?is:輸入流
//Rect?outPadding:用于返回矩形的內邊距
public?static?Bitmap?decodeStream(InputStream?is);
public?static?Bitmap?decodeStream(InputStream?is,Rect?outPadding,Options?opt);
//FileDescriptor?:包含解碼位圖的數據文件的路徑
//通過該方式從路徑加載bitmap比decodeFile更節省內存,原因不解釋了。
public?static?Bitmap?decodeFileDescriptor(FileDescriptor?fd);
public?static?Bitmap?decodeFileDescriptor(FileDescriptor?fd,Rect?outPadding,Options?opt);

平時用這些函數都是糊里糊涂的,今天整理了一遍發現其實有規律可尋,也更加清楚了。

3、Bitmap靜態方法

//width和height是長和寬單位px,config是存儲格式
static?Bitmap?createBitmap(int?width?,?int?height?Bitmap.Config?config)
//?根據一幅圖像創建一份一模一樣的實例
static?Bitmap?createBitmap(Bitmap?bm)
//截取一幅bitmap,起點是(x,y),width和height分別對應寬高
static?Bitmap?createBitmap(Bitmap?bm,int?x,int?y,int?width,int?height)
//比上面的裁剪函數多了兩個參數,Matrix:給裁剪后的圖像添加矩陣?boolean?filter:是否給圖像添加濾波效果
static?Bitmap?createBitmap(Bitmap?bm,int?x,int?y,int?width,int?height,Matrix?m,boolean?filter);
//用于縮放bitmap,dstWidth和dstHeight分別是目標寬高
createScaledBitmap(Bitmap?bm,int?dstWidth,int?dstHeight,boolean?filter)

4、創建Bitmap的總結

  • 加載圖像可以使用BitmapFactory和Bitmap.create系列方法

  • 可以通過Options實現縮放圖片,獲取圖片信息,配置縮放比例等功能

  • 如果需要裁剪或者縮放圖片,只能使用create系列函數

  • 注意加載和創建bitmap事通過try catch捕捉OOM異常

常見函數

1、函數及其參數

copy(Config?config,boolean?isMutable)
//根據原圖像創建一個副本,但可以指定副本的像素存儲格式
//參數含義。
//??config:像素在內存中的存儲格式,但可以指定副本的像素存儲格式
//??boolean?isMutable:新建的bitmap是否可以修改其中的像素值
extractAlpha()
//主要作用是從bitmap中獲取Alpha值,生成一幅只有Alpha值得圖像,存儲格式是ALPHA_8
getByteCount()//獲取bitmap的字節數
recycle()://不用的bitmap必須要及時回收,以免造成oom
isRecycled()//判斷bitmap是否被回收,被收回不可使用會造成crash

2、綜合案例演示

????????String?items[]?=?{"copy","extractAlpha?1","extractAlpha?2","bitmap大小","recycle","isRecycled()"};ArrayAdapter<String>?adapter?=?new?ArrayAdapter<>(this,?android.R.layout.simple_spinner_item,items);adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);spinner.setAdapter(adapter);spinner.setOnItemSelectedListener(new?AdapterView.OnItemSelectedListener()?{@Overridepublic?void?onItemSelected(AdapterView<?>?parent,?View?view,?int?position,?long?id)?{switch?(position){case?0://copyBitmap?bm?=?BitmapFactory.decodeResource(getResources(),?R.drawable.photo);Bitmap?copy?=?bm.copy(Bitmap.Config.ARGB_8888,?true);imageView.setImageBitmap(copy);bm.recycle();break;case?1://extractAlpha?不帶參數Bitmap?bp?=?BitmapFactory.decodeResource(getResources(),?R.drawable.photo);Bitmap?alpha?=?bp.extractAlpha();imageView.setImageBitmap(alpha);bp.recycle();break;case?2://extractAlpha?帶參數Bitmap?bp1?=?BitmapFactory.decodeResource(getResources(),?R.drawable.photo);Paint?paint?=?new?Paint();BlurMaskFilter?blurMaskFilter?=?new?BlurMaskFilter(6,?BlurMaskFilter.Blur.NORMAL);paint.setMaskFilter(blurMaskFilter);int[]?offsetXY?=?new?int[2];Bitmap?alpha1?=?bp1.extractAlpha(paint,?offsetXY);imageView.setImageBitmap(alpha1);break;case?3://獲取bitmap大小Bitmap?b?=?BitmapFactory.decodeResource(getResources(),?R.drawable.photo);Toast.makeText(getApplicationContext(),?"圖片大小為:"+b.getByteCount()+"字節",?Toast.LENGTH_SHORT).show();break;case?4://回收bitmapBitmap?b1?=?BitmapFactory.decodeResource(getResources(),?R.drawable.photo);b1.recycle();if(b1.isRecycled()){Toast.makeText(getApplicationContext(),?"已經被回收",?Toast.LENGTH_SHORT).show();}//isRecycled()判斷是否被回收break;}}@Overridepublic?void?onNothingSelected(AdapterView<?>?parent)?{}});

常見問題

1、Bitmap與Canvas,View,Drawable的關系:

  • 我們在創建一個Canvas時,可以傳入一個Bitmap,Paint在Canvas上的繪制實際上就是繪制在Bitmap對象上的。

  • 我們自定義空間所顯示的View也是通過Canvas中的Bitmap來顯示的。

  • Drawable在內存占用和繪制速度這兩個非常關鍵的點上勝過Bitmap。

2、使用Bitmap如何造成內存溢出的?

個人認為,Bitmap 容易造成內存溢出是由于位圖較大,一張屏幕大小的ARGB_8888 存儲格式的圖片竟然有24M,如果有幾個這種量級的圖片在內存中,并且沒有及時回收,那會非常容易造成 OOM。

3、怎么解決或者避免Bitmap內存溢出?

  • 我們可以對位圖進行壓縮,壓縮手段有 PNG,JPEG,WEBP。

  • 對不使用的 Bitmap 一定要及時回收。

  • 在創建 Bitmap 時使用 try catch 步驟 OOM 異常,使程序更健壯,即使發生了 OOM 也不會閃退,造成不好的使用體驗。

4、Bitmap與Drawable的轉換

(1)Drawable 轉換成 Bitmap

public?static?Bitmap?drawableToBitmap(Drawable?drawable)?{??//?取?drawable?的長寬??int?w?=?drawable.getIntrinsicWidth();??int?h?=?drawable.getIntrinsicHeight();??//?取?drawable?的顏色格式??Bitmap.Config?config?=?drawable.getOpacity()?!=?PixelFormat.OPAQUE???Bitmap.Config.ARGB_8888??:?Bitmap.Config.RGB_565;??//?建立對應?bitmap??Bitmap?bitmap?=?Bitmap.createBitmap(w,?h,?config);??//?建立對應?bitmap?的畫布??Canvas?canvas?=?new?Canvas(bitmap);??drawable.setBounds(0,?0,?w,?h);??//?把?drawable?內容畫到畫布中??drawable.draw(canvas);??return?bitmap;??}??

(2)Bitmap轉換成Drawable

Bitmap?bm=Bitmap.createBitmap(xxx);?
BitmapDrawable?bd=?new?BitmapDrawable(getResource(),?bm);

小結

?

以前使用?Bitmap 全靠 CV,現在掌握了這么多知識,Bitmap 隨便用都不會出現問題,媽媽再也不用擔心我內存溢出,太棒了!

版權聲明:本文為CSDN博主「?IF ?」的原創文章,遵循CC4.0 BY-SA版權協議,轉載請附上原文出處鏈接及本聲明。

原文鏈接:

https://blog.csdn.net/weixin_43927892/article/details/106209563

【END】

更多精彩推薦
?程序員之痛:六次創業五回失敗了
?Linux 之父怒刪工程師提交的補丁,稱“太蠢了”網友:懟得好!
?張一鳴是如何練就字節跳動的
?性能超越最新序列推薦模型,華為諾亞方舟提出記憶增強的圖神經網絡
?DevOps 在移動應用程序開發中扮演什么角色?
?穩定幣經濟:十大穩定幣簡史
你點的每個“在看”,我都認真當成了喜歡

版权声明:本站所有资料均为网友推荐收集整理而来,仅供学习和研究交流使用。

原文链接:https://hbdhgg.com/3/161522.html

发表评论:

本站为非赢利网站,部分文章来源或改编自互联网及其他公众平台,主要目的在于分享信息,版权归原作者所有,内容仅供读者参考,如有侵权请联系我们删除!

Copyright © 2022 匯編語言學習筆記 Inc. 保留所有权利。

底部版权信息