在android開(kāi)發(fā)中我們最常使用的繪制圖片的方式就是ImageView玩徊,設(shè)置src。那么有沒(méi)有其他方案可以實(shí)現(xiàn)圖片的繪制吶炕舵?
三種方案
- 通過(guò)Imageview設(shè)置setImageBitmap
final String path = Environment.getExternalStorageDirectory().getPath() + File.separator + "Pictures" + File.separator + "tmp.jpg";
Bitmap bitmap = BitmapFactory.decodeFile(path);
imageView.setImageBitmap(bitmap);
- 通過(guò)自定義View豪娜,定義Paint和讀取Bitmap吁津,然后在onDraw中用Canvas進(jìn)行drawBitamp
public class CustomView extends View {
private Paint paint;
private Bitmap bitmap;
public CustomView(Context context) {
this(context,null,0);
}
public CustomView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs,0);
}
public CustomView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
paint = new Paint();
paint.setAntiAlias(true);
paint.setStyle(Paint.Style.STROKE);
String path = Environment.getExternalStorageDirectory().getPath() + File.separator + "Pictures" + File.separator + "tmp.jpg";
bitmap = BitmapFactory.decodeFile(path);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if(bitmap!=null&&!bitmap.isRecycled()) {
canvas.drawBitmap(bitmap, 0, 0, paint);
}
}
}
- 通過(guò)SurfaceView棚蓄,通過(guò)surfaceView的SufaceHolder,拿到到canvas然后進(jìn)行繪制碍脏。
surfaceView.getHolder().addCallback(new SurfaceHolder.Callback() {
@Override
public void surfaceCreated(SurfaceHolder holder) {
if(holder == null){
return;
}
Paint paint = new Paint();
paint.setAntiAlias(true);
// paint.setStyle(Paint.Style.STROKE);
String path = Environment.getExternalStorageDirectory().getPath() + File.separator + "Pictures" + File.separator + "tmp.jpg";
Bitmap bitmap1 = BitmapFactory.decodeFile(path);
Canvas canvas = null;
try {
canvas = holder.lockCanvas();
canvas.drawBitmap(bitmap1,0,0,paint);
}catch (Exception e){
e.printStackTrace();
} finally {
if(canvas!=null){
holder.unlockCanvasAndPost(canvas);
}
}
Log.d(TAG, "surfaceCreated: ");
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
Log.d(TAG, "surfaceChanged: format"+format+" w="+width+" h="+height);
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
Log.d(TAG, "surfaceDestroyed: ");
}
});
SurfaceView和View的優(yōu)劣對(duì)比以及使用場(chǎng)景
通過(guò)上面的例子我們可以看到SurfaceView和View的使用的方式的區(qū)別梭依,View可以直接可以通過(guò)ImageView封裝的API或者View的onDraw中拿到Canvas進(jìn)行繪制。而SurfaceView則通過(guò)SurfaceHolder也是拿到Canvas進(jìn)行繪制典尾。
下嗎我們來(lái)說(shuō)下SurfaceView和view的區(qū)別
一個(gè)窗口中的所有view役拴,共享一個(gè)window,對(duì)應(yīng)一個(gè)surface(繪圖表面)surface中有個(gè)Canvas钾埂,可用于繪制河闰,在WMS中只可見(jiàn)頂層的DecorView科平,在WMS中對(duì)應(yīng)WindowState,app請(qǐng)求刷新Surface時(shí)姜性,會(huì)在SurfaceFlinger內(nèi)部建立對(duì)應(yīng)的Layer瞪慧。
優(yōu)點(diǎn):
- 可以在子線(xiàn)程繪制--》適用于被動(dòng)頻繁刷新的界面,比如視頻播放或者游戲
- 刷新只會(huì)刷新自己而不會(huì)刷新其他view所有在的viewHierchy部念,避免造成整個(gè)viewHierchy刷新弃酌,性能會(huì)更好。
- 雙緩沖機(jī)制儡炼,避免閃爍妓湘,提升性能。
缺點(diǎn): - view的動(dòng)畫(huà)對(duì)sureface無(wú)效
關(guān)閉window中所有view的硬件加速可以做到不透明的情況乌询。
如何使用:
Sureface.CallBack.
Sureface.getHolder
以及Sureface.lockCavas獲取到canvas進(jìn)行canvas操作然后sureface.unlockCavasAndPost進(jìn)行頁(yè)面的更新榜贴。
問(wèn)題:
為什么surfaceView不可見(jiàn)時(shí)會(huì)調(diào)用surfaceDestroyed,重新可見(jiàn)時(shí)有重新create楣责?
因?yàn)镾urfaceView的雙緩沖機(jī)制非常消耗內(nèi)存竣灌,Android規(guī)定SurfaceView不可見(jiàn)時(shí),會(huì)銷(xiāo)毀Surfaceview的SurfaceHolder秆麸,以達(dá)到節(jié)省系統(tǒng)資源的目的初嘹。
android10+存儲(chǔ)權(quán)限的獲取
在寫(xiě)該demo的時(shí)候,由于采用從外部存儲(chǔ)中讀取一種圖片進(jìn)行繪制沮趣,在獲取外部存儲(chǔ)權(quán)限的時(shí)候會(huì)遇到了麻煩屯烦,google對(duì)用戶(hù)權(quán)限的獲取越來(lái)越收斂,這是好事房铭。權(quán)限的授予用戶(hù)自己控制驻龟,在隱私安全上做了更好的保障。那么對(duì)于開(kāi)發(fā)者該如何獲取用戶(hù)的存儲(chǔ)權(quán)限吶缸匪?要做一下三步
- AndroidMainfest中注冊(cè)
- Application添加 android:requestLegacyExternalStorage="true"
- 通過(guò)AppOpsManager動(dòng)態(tài)的獲取
小結(jié)
通過(guò)本章翁狐,我們了解了繪制圖片根源都是在拿到Canvas然后在上面繪制bitmap。
可以通過(guò)ImageView提供的API凌蔬;可以通過(guò)自定義View露懒,在onDraw方法中進(jìn)行canvas的drawBitmap;也可以通過(guò)SurfaceView在onSurfaceCreate的時(shí)候通過(guò)surface的lockCanvas然后進(jìn)行canvas的drawbitmap砂心,最后在unlockCanvasAndPost到進(jìn)行繪制懈词。
SurfaceView和View最大的差異點(diǎn)在于,Surfaceview有自己?jiǎn)为?dú)的window辩诞,對(duì)應(yīng)WMS中有自己獨(dú)立的layer層坎弯,可以在子線(xiàn)程進(jìn)行繪制,刷新時(shí)不會(huì)影響所在的View樹(shù)結(jié)構(gòu)中的其他View,適用于被動(dòng)頻繁刷新的場(chǎng)景抠忘。相應(yīng)的劣勢(shì)是View的動(dòng)畫(huà)對(duì)Surfaceview無(wú)效撩炊,比如移動(dòng)縮放等,最明顯的表現(xiàn)就是有動(dòng)畫(huà)進(jìn)入或者滑動(dòng)退出有SurfaceView頁(yè)面時(shí)導(dǎo)致頁(yè)面透明褐桌。但是事實(shí)上在關(guān)閉View的硬件加速后是可以的衰抑。
關(guān)于Surfaceview的SurfaceHolder的生命周期,SurfaceView不可見(jiàn)時(shí)即進(jìn)行銷(xiāo)毀荧嵌,可見(jiàn)時(shí)再重新創(chuàng)建呛踊,原因在于SurfaceView采用了雙緩沖機(jī)制,做到了刷新是不閃爍啦撮。但是雙緩沖是比消耗內(nèi)存的谭网,所以android做了上述的策略。
Android10以上讀取sd卡的內(nèi)容等權(quán)限被google收斂赃春,首先要在AndroidManifest中注冊(cè)愉择,然后是使用前要?jiǎng)討B(tài)的獲取,在AndroidManifest的Application中也要加上
感謝閱讀织中。下一篇我們來(lái)分析學(xué)習(xí)下AudioTrack播放PCM锥涕,后續(xù)AudioRecord錄制PCM,歡迎關(guān)注交流狭吼。