知識
不管是網(wǎng)站,軟件還是小程序,都要直接或間接能為您產(chǎn)生價值,我們在追求其視覺表現(xiàn)的同時,更側重于功能的便捷,營銷的便利,運營的高效,讓網(wǎng)站成為營銷工具,讓軟件能切實提升企業(yè)內部管理水平和效率。優(yōu)秀的程序為后期升級提供便捷的支持!
[Android]浮層視頻效果,在另外一個Window使用SurfaceV
發(fā)表時間:2020-10-19
發(fā)布人:葵宇科技
瀏覽次數(shù):46
比來在勞碌視頻的工作,而視頻的繪制須要應用到SurfaceView。為了完成浮層效不雅,我們很天然的想到應用多Window的方法。然則問題就來了,當你將你的SurfaceView放置在別的一個window中的時刻,一切都變得不正常,為了驗證這個器械,我寫了一個小的demo:
[img]http://img.blog.csdn.net/20150104122520448?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvSGVsbG9fX1plcm8=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center
代碼異常簡單,按下中心那個按鈕,彈出一個Window,這個Window瑯綾擎存放一個簡單的SurfaceView,而這個Window的頂層View是一個FrameLayout。Window參數(shù)為:
private WindowManager.LayoutParams getWindowLayoutParams() { mWindowLayoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL; mWindowLayoutParams.setTitle("This is a test"); mWindowLayoutParams.width = WindowManager.LayoutParams.MATCH_PARENT; mWindowLayoutParams.height = WindowManager.LayoutParams.MATCH_PARENT; mWindowLayoutParams.flags |= WindowManager.LayoutParams.FLAG_FULLSCREEN | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN; mWindowLayoutParams.token = MainActivity.this.getWindow().getDecorView().getWindowToken(); return mWindowLayoutParams; }
好了,我們跑一下,就會發(fā)明界面沒有任何變更,然則界面上的按鈕都弗成點擊。這說清楚明了什么呢?說清楚明了你的Window已經(jīng)被體系窗口治理辦事所接收了,然則,界面顯示出問題。我們給SurfaceView 增長一個SurfaceView回調,并在surfaceCreated處打印Log。你會發(fā)明,這個回調根本沒有走。
@Override public void surfaceCreated(SurfaceHolder holder) { // TODO Auto-generated method stub Log.v("surface", "surfaceCreated"); }
這里我插入一灸┞封個回調的感化,這個回調的感化在于告訴你,SurfaceFlinger給你分派的Surface已經(jīng)可用了,然則這個回調不走,意味著當緇ご態(tài)下你的Surface處于弗采取的狀況,也就是SurfaceFlinger給你分派的Surface是弗采取的?;蛟S你到這里已經(jīng)一頭霧水了,不過沒緊要,@非子墨兄剛開端也有點好奇,不過你靜下來再想想,一個過程向SurfaceFlinger申請Surfacce并不是直接申請SurfaceFlinger辦事申請的,而是向WindowManager辦事申請的,也有可能是因為它引起的。我們在整頓一下我們碰到的問題。我們增長了一個Window到窗口治理,然則我們看到了一個透明且沒有surfacceCreate回調的SurfaceView。實際上這是兩個問題:一個問題是透明,一個是沒有回調。
我們先來解決第一個透明的問題,我們在頂層FrameLayout設置了背景后,發(fā)明照樣透明的,這是為什么呢?是因為SurfaceView這個對象申請顯示區(qū)域的時刻異常特別,并不是跟你的UI線程一個緩沖上疊加繪制,我們可以簡單懂得為它在UI線程所繪制的緩沖上開了個口兒,然后在本身的Buffer膳綾擎繪制。那么怎么解決透明的問題呢?其實異常異常的簡單,只須要給SurfaceView設置一個背景,告訴繪制辦事你的┞封個SurfaceView長短透明的就可以了。我給SurfaceView設置了一個藍色的背景,跑一下不雅然看到了效不雅:
[img]http://img.blog.csdn.net/20150104124346084?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvSGVsbG9fX1plcm8=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center
好了,如許我們解決了第一個問題:透明問題。再次我們來看下第二個問題,SurfaceView不回調的問題。我們剛才對Surface對象無效的問題都純屬于猜測,為了驗證我們的問題我們將SurfaceView中的Surface對象參數(shù)打印一下:
SurfaceView.java: private void updateWindow(boolean force, boolean redrawNeeded) { ... relayoutResult = mSession.relayout( mWindow, mWindow.mSeq, mLayout, mWidth, mHeight, visible ? VISIBLE : GONE, WindowManagerGlobal.RELAYOUT_DEFER_SURFACE_DESTROY, mWinFrame, mOverscanInsets, mContentInsets, mVisibleInsets, mConfiguration, mNewSurface); /*查看mSurface是否可用*/ booelan result = mSurface.isValid(); ... }不雅然不出我們所料,result的值為false。我們來看一下mSurface.isValid()的實現(xiàn):
public boolean isValid() { synchronized (mLock) { if (mNativeObject == 0) return false; return nativeIsValid(mNativeObject); } }
可見,mNativeObject對象句柄為null,也就是體系并沒有分派給你繪制內存句柄。這個時刻,不知道你會不會放棄,告訴本身這是體系的問題,實際上你離本相已經(jīng)很近了,只要再保持一會兒久煨。我們來看一下WMS的log:
W/WindowManager( 1154): Attempted to add window with token that is a sub-window: android.os.BinderProxy@432d6290. Aborting. W/WindowManager( 1154): Failed looking up window W/WindowManager( 1154): java.lang.IllegalArgumentException: Requested window android.os.BinderProxy@43296170 does not exist W/WindowManager( 1154): at com.android.server.wm.WindowManagerService.windowForClientLocked(WindowManagerService.java:7981) W/WindowManager( 1154): at com.android.server.wm.WindowManagerService.windowForClientLocked(WindowManagerService.java:7972) W/WindowManager( 1154): at com.android.server.wm.WindowManagerService.relayoutWindow(WindowManagerService.java:2784) W/WindowManager( 1154): at com.android.server.wm.Session.relayout(Session.java:190) W/WindowManager( 1154): at android.view.IWindowSession$Stub.onTransact(IWindowSession.java:235) W/WindowManager( 1154): at com.android.server.wm.Session.onTransact(Session.java:125) W/WindowManager( 1154): at android.os.Binder.execTransact(Binder.java:404) W/WindowManager( 1154): at dalvik.system.NativeStart.run(Native Method) W/WindowManager( 1154): Failed looking up window W/WindowManager( 1154): java.lang.IllegalArgumentException: Requested window android.os.BinderProxy@43296170 does not exist W/WindowManager( 1154): at com.android.server.wm.WindowManagerService.windowForClientLocked(WindowManagerService.java:7981) W/WindowManager( 1154): at com.android.server.wm.WindowManagerService.windowForClientLocked(WindowManagerService.java:7972) W/WindowManager( 1154): at com.android.server.wm.WindowManagerService.finishDrawingWindow(WindowManagerService.java:3105) W/WindowManager( 1154): at com.android.server.wm.Session.finishDrawing(Session.java:224) W/WindowManager( 1154): at android.view.IWindowSession$Stub.onTransact(IWindowSession.java:372) W/WindowManager( 1154): at com.android.server.wm.Session.onTransact(Session.java:125) W/WindowManager( 1154): at android.os.Binder.execTransact(Binder.java:404) W/WindowManager( 1154): at dalvik.system.NativeStart.run(Native Method)
我們粗淺的認為第二個客棧引起的原因是因為第一個客棧,而第一個客棧引起的原因有可能是因為這句話:
W/WindowManager( 1154): Attempted to add window with token that is a sub-window: android.os.BinderProxy@432d6290. Aborting.這個其實不算是一個異常,可以當成體系提示,也就是說它將我們的Window當成一個簡單的sub-window。我們看一下WMS這段代碼的實現(xiàn):
public int addWindow(Session session, IWindow client, int seq, WindowManager.LayoutParams attrs, int viewVisibility, int displayId, Rect outContentInsets, InputChannel outInputChannel) { ... if (attachedWindow.mAttrs.type >= FIRST_SUB_WINDOW && attachedWindow.mAttrs.type <= LAST_SUB_WINDOW) { Slog.w(TAG, "Attempted to add window with token that is a sub-window: " + attrs.token + ". Aborting."); return WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN; } ... if (addToken) { mTokenMap.put(attrs.token, token); } ... }
我們發(fā)明,當你以一個子Window的方法參加一個Window的時刻,體系辦事直接返回,如許就不克不及往mTokenMap中存放你的Token記錄,而這個token不存在,導致了膳綾擎兩個線程的異??蜅?。如許,我們離成功就只有一步之遙,我們已經(jīng)定位我們的問題出在這句話:
mWindowLayoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL;而我們只須要改成FIRST_SUB_WINDOW和LAST_SUB_WINDOW之外的值就可以解決問題了。這里我選用了TYPE_TOAST
private WindowManager.LayoutParams getWindowLayoutParams() { mWindowLayoutParams.type = WindowManager.LayoutParams.TYPE_TOAST; mWindowLayoutParams.setTitle("This is a test"); mWindowLayoutParams.width = WindowManager.LayoutParams.MATCH_PARENT; mWindowLayoutParams.height = WindowManager.LayoutParams.MATCH_PARENT; mWindowLayoutParams.flags |= WindowManager.LayoutParams.FLAG_FULLSCREEN | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN; mWindowLayoutParams.token = MainActivity.this.getWindow().getDecorView().getWindowToken(); return mWindowLayoutParams; }
如許,SurfaceView的回調就正常了,此刻一切問題都水到渠成。欲望這篇文┞仿能贊助到正在做這項功能的筒子們。
thx
相關案例查看更多
相關閱讀
- 網(wǎng)頁制作
- 云南網(wǎng)站開發(fā)
- 網(wǎng)站建設高手
- 軟件開發(fā)
- 昆明小程序設計
- 昆明小程序公司
- 云南小程序開發(fā)
- 網(wǎng)站建設專業(yè)品牌
- 報廢車管理系統(tǒng)
- APP
- 汽車報廢軟件
- 用戶登錄
- 曲靖小程序開發(fā)
- 網(wǎng)站建設公司哪家好
- 云南網(wǎng)站開發(fā)哪家好
- 微分銷
- 安家微信小程序
- 網(wǎng)站優(yōu)化
- 云南網(wǎng)站建設方案 doc
- web
- 云南建設廳網(wǎng)站首頁
- 云南網(wǎng)站建設首選公司
- 怎么做網(wǎng)站
- 網(wǎng)站建設方案 doc
- 網(wǎng)站建設制作
- 汽車拆解管理系統(tǒng)
- 云南小程序開發(fā)制作公司
- 公眾號模板消息
- 報廢車拆解管理系統(tǒng)
- 網(wǎng)站建設靠譜公司