【问题标题】:is there a way to disable hardware acceleration only for android 4.0.3?有没有办法只为 android 4.0.3 禁用硬件加速?
【发布时间】:2012-12-12 23:09:36
【问题描述】:

我最近偶然发现了 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禁用硬件加速,或者是否有解决方法?

感谢您的宝贵时间。

【问题讨论】:

  • 有一种方法可以根据 API 来disable。这是他们提供的代码:myView.setLayerType(View.LAYER_TYPE_SOFTWARE, null); 你需要一个 if 语句来检查 API 版本,然后使用上面的代码。
  • @A--C 谢谢,这需要为每个视图执行此操作,是否可以使用代码在应用程序级别更改它,我的意思是在 AndroidManifest 文件之外?
  • 我不这么认为,看来您只能指定您的应用程序是硬件加速的并且它是全球性的,没有特定的 API 版本。您可以做的一件事是创建一个特殊的 API 布局文件夹(layout-v13 或任何 4.03 的 API)并在 xml 中设置每个视图的 layer 类型。

标签: android android-4.0-ice-cream-sandwich


【解决方案1】:

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

只启用它。我建议您在清单中默认禁用它:

<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 - Controlling Hardware Acceleration获取

【讨论】:

  • 重要提示:Android 开发人员还说:“请务必记住,必须在设置活动或对话框的内容视图之前设置此标志(指“FLAG_HARDWARE_ACCELERATED”)。”
【解决方案2】:

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

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”,以便使用此方法设置正确的值?
  • 系统怎么知道isNotIceCreamSandwich的版本号?
【解决方案3】:

所以 A-C 在他的评论中提到了这一点,但让我详细说明一下。

您可以在值文件中创建一个布尔值并将其粘贴到正确的版本文件夹中。在你的清单下

查看这篇文章:https://plus.google.com/+AndroidDevelopers/posts/DcsFABkyuYM

看起来你想要定位 values-v15/bools.xml

http://developer.android.com/reference/android/os/Build.VERSION_CODES.html#ICE_CREAM_SANDWICH_MR1

【讨论】:

  • 谢谢,我试试这个,这是 4.0.3 的常见问题吗?显然,对于 2d 视图,硬件加速在 4.0.3 上不是那么稳定。
  • 我不确定,也许我是通过解决您提出的问题而不是找到加速问题的实际解决方案来抢先一步。在使用此解决方案之前,我会继续调查。
【解决方案4】:

这是一个有趣的错误,因为硬件加速正在工作(有时)。这两天我一直在寻找这个问题的答案。它记录在 ICS 中,但我在我的一部测试手机中注意到它,运行 4.1.2 的三星 Galaxy S3 大多数人建议关闭硬件加速。我不想这样做,因为硬件加速使我的动画非常流畅。所以我发现如果我重写 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。我第一次看到这个错误时,我将整个 draw() 代码包围在一个 try and catch 中。这适用于大多数手机,但在运行 4.1.2 的三星 s3 上会导致闪烁。因此,我使用了上述方法,并在每次调用 someObject.draw(mCanvas) 时都进行了静默 try catch,这完全解决了问题,消除了所有闪烁(硬件加速视图缓存和新画布之间的差异)。希望这可以帮助!比关闭 HWA 好多了!

【讨论】:

    猜你喜欢
    • 2021-10-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-19
    • 2013-12-31
    相关资源
    最近更新 更多