SurfaceView原理理解和常見問題

在Android系統(tǒng)中,有一種特殊的視圖地淀,稱為SurfaceView嬉探。

什么場(chǎng)景選用SurfaceView

SurfaceView概念:
SurfaceView本身是一個(gè)View,符合一切View的特性排惨,需要通過(guò)Canvas畫布繪制。
developer官方文檔對(duì)SurfaceView的定義

Provides a dedicated drawing surface embedded inside of a view hierarchy. You can control the format of this surface and, if you like, its size; the SurfaceView takes care of placing the surface at the correct location on the screen
The surface is Z ordered so that it is behind the window holding its SurfaceView; the SurfaceView punches a hole in its window to allow its surface to be displayed. The view hierarchy will take care of correctly compositing with the Surface any siblings of the SurfaceView that would normally appear on top of it. This can be used to place overlays such as buttons on top of the Surface, though note however that it can have an impact on performance since a full alpha-blended composite will be performed each time the Surface changes.
The transparent region that makes the surface visible is based on the layout positions in the view hierarchy. If the post-layout transform properties are used to draw a sibling view on top of the SurfaceView, the view may not be properly composited with the surface.

總結(jié)幾個(gè)要點(diǎn):

  1. SurfaceView擁有獨(dú)立的Surface(繪圖表面)
  2. SurfaceView是用Zorder排序的碰凶,他默認(rèn)在宿主Window的后面暮芭,SurfaceView通過(guò)在Window上面“挖洞”(設(shè)置透明區(qū)域)進(jìn)行顯示

SurfaceView與View的區(qū)別

  • View的繪圖效率不高鹿驼,主要用于動(dòng)畫變化較少的程序
  • SurfaceView 繪圖效率較高,用于界面更新頻繁的程序
  • SurfaceView擁有獨(dú)立的Surface(繪圖表面)辕宏,即它不與其宿主窗口共享同一個(gè)Surface畜晰。
    一般來(lái)說(shuō),每一個(gè)窗口在SurfaceFlinger服務(wù)中都對(duì)應(yīng)有一個(gè)Layer瑞筐,用來(lái)描述它的繪圖表面凄鼻。對(duì)于那些具有SurfaceView的窗口來(lái)說(shuō),每一個(gè)SurfaceView在SurfaceFlinger服務(wù)中還對(duì)應(yīng)有一個(gè)獨(dú)立的Layer或者LayerBuffer聚假,用來(lái)單獨(dú)描述它的繪圖表面块蚌,以區(qū)別于它的宿主窗口的繪圖表面。
    因此SurfaceView的UI就可以在一個(gè)獨(dú)立的線程中進(jìn)行繪制膘格,可以不會(huì)占用主線程資源匈子。
  • SurfaceView使用雙緩沖機(jī)制,播放視頻時(shí)畫面更流暢

什么是雙緩沖機(jī)制

在運(yùn)用時(shí)可以理解為:SurfaceView在更新視圖時(shí)用到了兩張 Canvas闯袒,一張 frontCanvas 和一張 backCanvas 虎敦,每次實(shí)際顯示的是 frontCanvas ,backCanvas 存儲(chǔ)的是上一次更改前的視圖政敢。當(dāng)你在播放這一幀的時(shí)候其徙,它已經(jīng)提前幫你加載好后面一幀了,所以播放起視頻很流暢喷户。
當(dāng)使用lockCanvas()獲取畫布時(shí)唾那,得到的實(shí)際上是backCanvas 而不是正在顯示的 frontCanvas ,之后你在獲取到的 backCanvas 上繪制新視圖褪尝,再 unlockCanvasAndPost(canvas)此視圖闹获,那么上傳的這張 canvas 將替換原來(lái)的 frontCanvas 作為新的frontCanvas ,原來(lái)的 frontCanvas 將切換到后臺(tái)作為 backCanvas 河哑。例如避诽,如果你已經(jīng)先后兩次繪制了視圖A和B,那么你再調(diào)用 lockCanvas()獲取視圖璃谨,獲得的將是A而不是正在顯示的B沙庐,之后你將重繪的 A 視圖上傳,那么 A 將取代 B 作為新的 frontCanvas 顯示在SurfaceView 上佳吞,原來(lái)的B則轉(zhuǎn)換為backCanvas拱雏。
相當(dāng)與多個(gè)線程,交替解析和渲染每一幀視頻數(shù)據(jù)底扳。

使用場(chǎng)景

所以SurfaceView一方面可以實(shí)現(xiàn)復(fù)雜而高效的UI铸抑,另一方面又不會(huì)導(dǎo)致用戶輸入得不到及時(shí)響應(yīng)。常用于畫面內(nèi)容更新頻繁的場(chǎng)景衷模,比如游戲鹊汛、視頻播放和相機(jī)預(yù)覽菇爪。

使用SurfaceView的三步驟

如何使用SurfaceView呢?

1柒昏、獲取SurfaceHolder對(duì)象凳宙,其是SurfaceView的內(nèi)部類。添加回調(diào)監(jiān)聽Surface生命周期职祷。

mSurfaceHolder = getHolder();
mSurfaceHolder.addCallback(this);

2氏涩、surfaceCreated 回調(diào)后啟動(dòng)繪制線程
只有當(dāng)native層的Surface創(chuàng)建完畢之后,才可以調(diào)用lockCanvas()有梆,否則失敗是尖。

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        mDrawThread = new DrawThread();
        mDrawThread.start();
    }

3、繪制

      Canvas canvas = mSurfaceHolder.lockCanvas();
      // 使用canvas繪制內(nèi)容 
      ...
      mSurfaceHolder.unlockCanvasAndPost(canvas);

使用SurfaceView不顯示問題

發(fā)生這種問題的原因是多層嵌套被遮擋
解決方法是根據(jù)具體情況調(diào)用如下api接口:

setZOrderOnTop(boolean onTop) // 在最頂層泥耀,會(huì)遮擋一切view
setZOrderMediaOverlay(boolean isMediaOverlay)// 如已繪制SurfaceView則在surfaceView上一層繪制饺汹。

看下他們的源碼:

    public void setZOrderMediaOverlay(boolean isMediaOverlay) {
        mSubLayer = isMediaOverlay
            ? APPLICATION_MEDIA_OVERLAY_SUBLAYER : APPLICATION_MEDIA_SUBLAYER;
    }

    public void setZOrderOnTop(boolean onTop) {
        if (onTop) {
            mSubLayer = APPLICATION_PANEL_SUBLAYER;
        } else {
            mSubLayer = APPLICATION_MEDIA_SUBLAYER;
        }
    }

兩個(gè)方法都是給mSubLayer賦值,所以需要注意這兩個(gè)接口同時(shí)調(diào)用后一個(gè)會(huì)覆蓋前一個(gè)的效果痰催。

黑色背景問題

    //設(shè)置背景透明
    mHolder.setFormat(PixelFormat.TRANSPARENT);
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末兜辞,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子夸溶,更是在濱河造成了極大的恐慌逸吵,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,525評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件缝裁,死亡現(xiàn)場(chǎng)離奇詭異扫皱,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)捷绑,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,203評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門韩脑,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人粹污,你說(shuō)我怎么就攤上這事段多。” “怎么了厕怜?”我有些...
    開封第一講書人閱讀 164,862評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵衩匣,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我粥航,道長(zhǎng),這世上最難降的妖魔是什么生百? 我笑而不...
    開封第一講書人閱讀 58,728評(píng)論 1 294
  • 正文 為了忘掉前任递雀,我火速辦了婚禮,結(jié)果婚禮上蚀浆,老公的妹妹穿的比我還像新娘缀程。我一直安慰自己搜吧,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,743評(píng)論 6 392
  • 文/花漫 我一把揭開白布杨凑。 她就那樣靜靜地躺著滤奈,像睡著了一般。 火紅的嫁衣襯著肌膚如雪撩满。 梳的紋絲不亂的頭發(fā)上蜒程,一...
    開封第一講書人閱讀 51,590評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音伺帘,去河邊找鬼昭躺。 笑死,一個(gè)胖子當(dāng)著我的面吹牛伪嫁,可吹牛的內(nèi)容都是我干的领炫。 我是一名探鬼主播,決...
    沈念sama閱讀 40,330評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼张咳,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼帝洪!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起脚猾,我...
    開封第一講書人閱讀 39,244評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤碟狞,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后婚陪,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體族沃,經(jīng)...
    沈念sama閱讀 45,693評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,885評(píng)論 3 336
  • 正文 我和宋清朗相戀三年泌参,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了脆淹。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,001評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡沽一,死狀恐怖盖溺,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情铣缠,我是刑警寧澤烘嘱,帶...
    沈念sama閱讀 35,723評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站蝗蛙,受9級(jí)特大地震影響蝇庭,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜捡硅,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,343評(píng)論 3 330
  • 文/蒙蒙 一哮内、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧壮韭,春花似錦北发、人聲如沸纹因。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,919評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)瞭恰。三九已至,卻和暖如春狱庇,著一層夾襖步出監(jiān)牢的瞬間惊畏,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,042評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工僵井, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留陕截,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,191評(píng)論 3 370
  • 正文 我出身青樓批什,卻偏偏與公主長(zhǎng)得像农曲,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子驻债,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,955評(píng)論 2 355

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