Android layer type与WebView白屏以及WebView不随动画而动的问题

转自:http://blog.csdn.net/a345017062/article/details/7478667

问题:WebView白屏(有数据)

报错:[ERROR:in_process_view_renderer.cc(189)] Failed to request GL process. Deadlock likely: 0

解决:WebView设置setLayerType(View.LAYER_TYPE_SOFTWARE,null)

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
            setLayerType(View.LAYER_TYPE_SOFTWARE, null);
        }
分析:WebView继承View,View中有三种layer type分别为

    /**
     * Indicates that the view does not have a layer.
     *
     * @see #getLayerType()
     * @see #setLayerType(int, android.graphics.Paint)
     * @see #LAYER_TYPE_SOFTWARE
     * @see #LAYER_TYPE_HARDWARE
     */
    public static final int LAYER_TYPE_NONE = 0;

    /**
     * <p>Indicates that the view has a software layer. A software layer is backed
     * by a bitmap and causes the view to be rendered using Android's software
     * rendering pipeline, even if hardware acceleration is enabled.</p>
     *
     * <p>Software layers have various usages:</p>
     * <p>When the application is not using hardware acceleration, a software layer
     * is useful to apply a specific color filter and/or blending mode and/or
     * translucency to a view and all its children.</p>
     * <p>When the application is using hardware acceleration, a software layer
     * is useful to render drawing primitives not supported by the hardware
     * accelerated pipeline. It can also be used to cache a complex view tree
     * into a texture and reduce the complexity of drawing operations. For instance,
     * when animating a complex view tree with a translation, a software layer can
     * be used to render the view tree only once.</p>
     * <p>Software layers should be avoided when the affected view tree updates
     * often. Every update will require to re-render the software layer, which can
     * potentially be slow (particularly when hardware acceleration is turned on
     * since the layer will have to be uploaded into a hardware texture after every
     * update.)</p>
     *
     * @see #getLayerType()
     * @see #setLayerType(int, android.graphics.Paint)
     * @see #LAYER_TYPE_NONE
     * @see #LAYER_TYPE_HARDWARE
     */
    public static final int LAYER_TYPE_SOFTWARE = 1;

    /**
     * <p>Indicates that the view has a hardware layer. A hardware layer is backed
     * by a hardware specific texture (generally Frame Buffer Objects or FBO on
     * OpenGL hardware) and causes the view to be rendered using Android's hardware
     * rendering pipeline, but only if hardware acceleration is turned on for the
     * view hierarchy. When hardware acceleration is turned off, hardware layers
     * behave exactly as {@link #LAYER_TYPE_SOFTWARE software layers}.</p>
     *
     * <p>A hardware layer is useful to apply a specific color filter and/or
     * blending mode and/or translucency to a view and all its children.</p>
     * <p>A hardware layer can be used to cache a complex view tree into a
     * texture and reduce the complexity of drawing operations. For instance,
     * when animating a complex view tree with a translation, a hardware layer can
     * be used to render the view tree only once.</p>
     * <p>A hardware layer can also be used to increase the rendering quality when
     * rotation transformations are applied on a view. It can also be used to
     * prevent potential clipping issues when applying 3D transforms on a view.</p>
     *
     * @see #getLayerType()
     * @see #setLayerType(int, android.graphics.Paint)
     * @see #LAYER_TYPE_NONE
     * @see #LAYER_TYPE_SOFTWARE
     */
    public static final int LAYER_TYPE_HARDWARE = 2;


LAYER_TYPE_NONE:表明视图没有多余渲染层。

LAYER_TYPE_SOFTWARE:表明视图有一个软件渲染层。无论是否开启硬件加速,都会有一张Bitmap(software layer),并在上面对WebView进行渲染。

好处:在进行动画,使用software可以只画一次View树,很省。

什么时候不要用:

View树经常更新时不要用。尤其是在硬件加速打开时,每次更新消耗的时间更多。因为渲染完这张Bitmap后还需要再把这张Bitmap渲染到hardware layer上面去。

LAYER_TYPE_HARDWARE:

表明视图有一个硬件渲染层。硬件加速关闭时,作用同software。硬件加速打开时会在FBO(Framebuffer Object)上做渲染,在进行动画时,View树也只需要画一次。

两者区别:

1.一个是渲染到Bitmap,一个是渲染到FB上。

2.hardware可能会有一些操作不支持(出现白屏)

两者相同:

都是开了一个buffer,把View画到这个buffer上面去。

PS:GLSurfaceView和WebView默认LayerType都是NONE。


GLSurfaceView:给GLSurfaceView设置为software或者hardware后,发现什么也画不出来了。得出结论:GLSurfaceView的LayerType只能是NONE。


WebView:

以前使用WebView时碰到过一个问题,如果在WebView上面使用Animation,WebView的绘画区域不动。当时的解决方案是在进行动画之前对WebView进行截屏(drawingcache)。按上面的道理试了一下,设置一个hardware或者software的layer就OK了。

现在又碰到了另外一个问题,打开硬件加速后,在一些机器上面(我的是3.2及HTC 4.4)WebView有时会出现某一块区域白屏的问题。默认的LayerType是NONE,改为hardware也不行,设置为software就解决了。当然关闭硬件加速也好了,可是那样的话程序整体就比较慢了。所以最终方案是整体硬件加速,出问题的WebView设置software。


补充1:

加上这一句,可以让3D的绘制更快一些:getHolder().setType(SurfaceHolder.SURFACE_TYPE_HARDWARE);

补充2:

问题:

在硬件加速开启的情况下GLSurfaceView一旦被从View树上摘下来,会使整个窗口背景变黑,即使设置LayerType为software也不管用。

经过两天的排查,发现了原因,我的程序是在C层由drawFrame(属于GLThread线程)来驱动进行绘画,当时GLSurfaceView被摘下来时,GLSurfaceView的destroy方法被调用,我在destory方法(属于UI线程)中直接调用了GLThread线程的结束方法。而GLSurfaceView.creat, sizeChanged,destroyed在UI线程,Render.create,sizeChanged,drawFrame在GLThread线程。因此,出现了UI线程直接调用GLThread线程的方法问题。最终通过GLSurfaceView.queueEvent向GLThread线程发送Runnable,问题得到解决。

看来,还是软渲染的容错能力比较强,一开硬件加速,底层就比较脆弱了。

结论:一定要搞清楚哪个是UI线程,哪个是GLThread线程。


补充以上寻找问题过程中发现的知识点:

hardware acclerator是对整个窗口进行加速,在硬件加速打开时View.isHardwareAcclerator返回true。但每个View可能被渲染到的Canvas是不同的,比如View可能被通过setLayer设置layer,这时,Canvas.isHardwareAccelerator返回false

Android提供了三种硬件加速是否开启的控制级别,分别是Application,Activity,Window,View。这个可以参考DevGuide。


你可能感兴趣的:(动画,android,webView)