[Android]浮层视频效果,在另外一个Window使用SurfaceV - 新闻资讯 - 云南小程序开发|云南软件开发|云南网站建设-昆明葵宇信息科技有限公司

159-8711-8523

云南网建设/小程序开发/软件开发

知识

不管是网站,软件还是小程序,都要直接或间接能为您产生价值,我们在追求其视觉表现的同时,更侧重于功能的便捷,营销的便利,运营的高效,让网站成为营销工具,让软件能切实提升企业内部管理水平和效率。优秀的程序为后期升级提供便捷的支持!

您当前位置>首页 » 新闻资讯 » 技术分享 >

[Android]浮层视频效果,在另外一个Window使用SurfaceV

发表时间:2020-10-19

发布人:葵宇科技

浏览次数:30


       比来在劳碌视频的工作,而视频的绘制须要应用到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参数为:
   
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;
    }

好了,我们跑一下,就会发明界面没有任何变更,然则界面上的按钮都弗成点击。这说清楚明了什么呢?说清楚明了你的Window已经被体系窗口治理办事所接收了,然则,界面显示出问题。我们给SurfaceView 增长一个SurfaceView回调,并在surfaceCreated处打印Log。你会发明,这个回调根本没有走。
@Override
	public void surfaceCreated(SurfaceHolder holder) {
		// TODO Auto-generated method stub
		Log.v("surface", "surfaceCreated");
	}

这里我插入一灸┞封个回调的感化,这个回调的感化在于告诉你,SurfaceFlinger给你分派的Surface已经可用了,然则这个回调不走,意味着当缁ご态下你的Surface处于弗采取的状况,也就是SurfaceFlinger给你分派的Surface是弗采取的。或许你到这里已经一头雾水了,不过没紧要,@非子墨兄刚开端也有点好奇,不过你静下来再想想,一个过程向SurfaceFlinger申请Surfacce并不是直接申请SurfaceFlinger办事申请的,而是向WindowManager办事申请的,也有可能是因为它引起的。我们在整顿一下我们碰到的问题。我们增长了一个Window到窗口治理,然则我们看到了一个透明且没有surfacceCreate回调的SurfaceView。实际上这是两个问题:一个问题是透明,一个是没有回调。
   我们先来解决第一个透明的问题,我们在顶层FrameLayout设置了背景后,发明照样透明的,这是为什么呢?是因为SurfaceView这个对象申请显示区域的时刻异常特别,并不是跟你的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对象参数打印一下:
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()的实现:

public boolean isValid() {
        synchronized (mLock) {
            if (mNativeObject == 0) return false;
            return nativeIsValid(mNativeObject);
        }
    }

可见,mNativeObject对象句柄为null,也就是体系并没有分派给你绘制内存句柄。这个时刻,不知道你会不会放弃,告诉本身这是体系的问题,实际上你离本相已经很近了,只要再保持一会儿久煨。我们来看一下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这段代码的实现:

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);
            }
...
}

我们发明,当你以一个子Window的方法参加一个Window的时刻,体系办事直接返回,如许就不克不及往mTokenMap中存放你的Token记录,而这个token不存在,导致了膳绫擎两个线程的异常客栈。如许,我们离成功就只有一步之遥,我们已经定位我们的问题出在这句话:

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


         

相关案例查看更多