有没有一种方法只针对Android 4.0.3禁用硬件加速?

18

最近我在使用Android 4.0.3时遇到了一个问题,应用程序一启动就会出现以下异常(在其他版本的Android上运行正常):

java.lang.NullPointerException
at android.view.GLES20RecordingCanvas.drawPatch(GLES20RecordingCanvas.java:97)
at android.graphics.NinePatch.draw(NinePatch.java:125)
at android.graphics.drawable.NinePatchDrawable.draw(NinePatchDrawable.java:189)
at android.widget.ImageView.onDraw(ImageView.java:892)
at android.view.View.draw(View.java:10978)
at android.view.ViewGroup.drawChild(ViewGroup.java:2887)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:2489)
at android.view.ViewGroup.drawChild(ViewGroup.java:2885)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:2489)
at android.view.View.getDisplayList(View.java:10415)
at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:2597)
at android.view.View.getDisplayList(View.java:10380)
at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:2597)
at android.view.View.getDisplayList(View.java:10380)
at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:2597)
at android.view.View.getDisplayList(View.java:10380)
at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:2597)
at android.view.View.getDisplayList(View.java:10380)
at android.view.HardwareRenderer$GlRenderer.draw(HardwareRenderer.java:842)
at android.view.ViewRootImpl.draw(ViewRootImpl.java:1910)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1634)
at android.view.ViewRootImpl.handleMessage(ViewRootImpl.java:2442)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4424)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
at dalvik.system.NativeStart.main(Native Method)

这与启用硬件加速有关,一旦我在清单上禁用它,应用程序就可以正常工作了。
通过搜索,我找到了Romain Guy的一些对话log(在该文档中搜索“drawPatch”),他在其中讨论了可能导致此问题的原因,尽管没有提出解决方法或修复建议,但我想知道是否应该仅为此Android版本禁用硬件加速,或者是否有解决方法?
感谢您的时间。

2
有一种方法可以根据API 禁用。这是他们提供的代码:myView.setLayerType(View.LAYER_TYPE_SOFTWARE, null); 您需要一个if语句来检查API版本,然后使用上面的代码。 - A--C
@A--C 谢谢,这需要为每个视图都做一遍,有没有可能在应用程序级别使用代码进行更改,也就是在 AndroidManifest 文件之外? - Aldo Reyes
我认为不行,似乎你只能指定你的应用程序是硬件加速的并且是全局的,没有特定的API版本。你可以做的一件事是创建一个特殊的API布局文件夹(例如layout-v13或4.03的API),并在xml中设置每个视图的层类型。layer - A--C
4个回答

25

目前您无法通过代码在窗口级别上禁用硬件加速。

只能启用它。我建议您在清单文件中将其默认禁用:

<application android:hardwareAccelerated="false">
    <activity ... />
    <activity android:hardwareAccelerated="false" />
</application>

然后使其适用于所有其他版本:

if (Build.VERSION.SDK_INT != Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
            getWindow().setFlags(
                    WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED,
                    WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);
        }

您可以使用以下代码在运行时禁用单个视图的硬件加速:

您可以使用以下代码在运行时禁用单个视图的硬件加速:

myView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);

这些信息可以在Android - 控制硬件加速中找到。


1
重要提示:Android开发者也指出:“在设置活动或对话框的内容视图之前,必须设置此标志(指“FLAG_HARDWARE_ACCELERATED”)。” - MBDevelop

18

我喜欢@sgarman提供的答案,因为它对代码的影响最小且易于维护。以下是对该链接的扩展,这是我为仅对Android v4.0.3中特定活动禁用硬件加速所做的(请记得将指定版本和编码的 XML 头添加到各种 bool.xml 文件中,因为维基编辑器不允许我将其粘贴到其中):

AndroidManifest.xml:识别承载有问题视图的活动,并将此代码插入到该活动中:

<activity
    android:hardwareAccelerated="@bool/isNotIceCreamSandwich"
    ...
</activity>

文件路径:res/values/bool.xml:

<resources>
    <bool name="isNotIceCreamSandwich">true</bool>
</resources>

文件路径:res/values-v14/bool.xml:

<resources>
    <bool name="isNotIceCreamSandwich">false</bool>
</resources>

文件路径: res/values-v16/bool.xml:

<resources>
    <bool name="isNotIceCreamSandwich">true</bool>
</resources>

有没有一种方法可以在布局XML文件中设置“android:layerType”,以便使用此方法设置正确的值? - android developer
系统如何知道 isNotIceCreamSandwich 版本代码? - Shailendra Madda

9

谢谢,我会尝试这个。这是4.0.3常见的问题吗?显然,在2D视图上硬件加速不太稳定。 - Aldo Reyes
我不确定,也许我过早地解决了你提出的问题,而没有找到加速问题的实际解决方案。在使用这个解决方案之前,我会继续调查。 - sgarman

5

这是一个有趣的错误,因为硬件加速正在工作(有时)。我已经搜索了最近几天的答案。它在ICS中有记录,但我注意到在我的测试手机三星Galaxy S3上运行4.1.2也存在。大多数人建议关闭硬件加速。我不想这样做,因为硬件加速使我的动画非常流畅。所以我发现如果我覆盖draw()并捕获null指针异常,硬件加速功能就会工作(大部分时间),而且足够让你永远不会注意到它们没有工作或抛出异常。

在我的情况下,我正在进行自定义视图,并需要进行一些自定义绘制。简单的空值检查(canvas==null)无法解决问题,这就是为什么这个bug很麻烦的原因。所以我做的是:

    @Override
public void draw(Canvas canvas) {
    try{
        super.draw(canvas);
        mCanvas=canvas;
    }catch(java.lang.NullPointerException e){
        Log.e("mytag","MyCustomView::draw():"+e);
    }
    if(mCanvas==null)
        return;     
...

然后悄无声息地尝试并捕获个别绘制语句中的任何NPE。第一次看到这个bug时,我将整个draw()代码都包围在一个try和catch中。这对大多数手机都有效,但在运行4.1.2的三星s3上会出现闪烁。因此,我使用了上述方法,并在每次调用someObject.draw(mCanvas)时进行了静默的try catch处理,完全解决了问题(硬件加速视图缓存与新画布之间的差异)。希望这可以帮助你!比关闭HWA要好得多!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接