错误:DisplayListCanvas.throwIfCannotDraw中的RuntimeException

32

我的应用程序在Nougat模拟器和许多设备上运行得非常良好,但我发现在Google Play崩溃报告中出现了这个异常,我不知道为什么会发生这种情况。这个异常只会发生在Nougat设备上++。

异常信息:

   java.lang.RuntimeException: 
  at android.view.DisplayListCanvas.throwIfCannotDraw(DisplayListCanvas.java:260)
  at android.graphics.Canvas.drawBitmap(Canvas.java:1420)
  at android.graphics.drawable.BitmapDrawable.draw(BitmapDrawable.java:545)
  at android.view.View.getDrawableRenderNode(View.java:18591)
  at android.view.View.drawBackground(View.java:18527)
  at android.view.View.draw(View.java:18315)
  at android.view.View.updateDisplayListIfDirty(View.java:17302)
  at android.view.View.draw(View.java:18086)
  at android.view.ViewGroup.drawChild(ViewGroup.java:3966)
  at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3752)
  at android.view.View.updateDisplayListIfDirty(View.java:17297)
  at android.view.View.draw(View.java:18086)
  at android.view.ViewGroup.drawChild(ViewGroup.java:3966)
  at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3752)
  at android.view.View.updateDisplayListIfDirty(View.java:17297)
  at android.view.View.draw(View.java:18086)
  at android.view.ViewGroup.drawChild(ViewGroup.java:3966)
  at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3752)
  at android.view.View.updateDisplayListIfDirty(View.java:17297)
  at android.view.View.draw(View.java:18086)
  at android.view.ViewGroup.drawChild(ViewGroup.java:3966)
  at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3752)
  at android.view.View.updateDisplayListIfDirty(View.java:17297)
  at android.view.View.draw(View.java:18086)
  at android.view.ViewGroup.drawChild(ViewGroup.java:3966)
  at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3752)
  at android.view.View.draw(View.java:18327)
  at com.android.internal.policy.DecorView.draw(DecorView.java:919)
  at android.view.View.updateDisplayListIfDirty(View.java:17302)
  at android.view.ThreadedRenderer.updateViewTreeDisplayList(ThreadedRenderer.java:692)
  at android.view.ThreadedRenderer.updateRootDisplayList(ThreadedRenderer.java:698)
  at android.view.ThreadedRenderer.draw(ThreadedRenderer.java:806)
  at android.view.ViewRootImpl.draw(ViewRootImpl.java:3135)
  at android.view.ViewRootImpl.performDraw(ViewRootImpl.java:2931)
  at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2523)
  at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1522)
  at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:7098)
  at android.view.Choreographer$CallbackRecord.run(Choreographer.java:927)
  at android.view.Choreographer.doCallbacks(Choreographer.java:702)
  at android.view.Choreographer.doFrame(Choreographer.java:638)
  at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:913)
  at android.os.Handler.handleCallback(Handler.java:751)
  at android.os.Handler.dispatchMessage(Handler.java:95)
  at android.os.Looper.loop(Looper.java:154)
  at android.app.ActivityThread.main(ActivityThread.java:6682)
  at java.lang.reflect.Method.invoke(Native Method:0)
  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1520)
  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1410)

这个错误可能是什么?

注意:我使用的所有可绘制对象都小于1MB


9
我跟三星Galaxy S6、S7和S8有完全相同的问题。如果您找到了解决方法,请与我们分享。 - Ramdane Oualitsen
我曾经遇到过相同的问题,试试这个链接,也许可以节省很多寻找解决方案的时间:https://dev59.com/s1kT5IYBdhLWcg3wELgl - Divyanshu Kumar
6个回答

25

我曾经遇到过与 Samsung Galaxy S6 S7 S8 相同的问题。在我的情况下,启动画面具有高分辨率,并且错误地放置在了drawable文件夹中。我从 这个 答案中找到了解决方案。

  1. 右键单击 drawable -> New -> Directory.
  2. 输入新目录名称:xxhdpi。如果您进入res文件夹,它将创建一个名为drawable-xxhdpi的新文件夹。
  3. 将您的启动画面从drawable移动到drawable-xxhdpi文件夹中。

我在三星S7和J7上遇到了相同的问题,我尝试了这个解决方案。但仍然出现相同的错误。 - Aashish Kumar
这个逻辑解决了我的问题,适用于三星S6和Sdks 21、22、23和24,分辨率为1440x2560,像素密度为640 dpi(xxxhdpi)。我创建了一个drawable-xxxhdpi文件夹,并将启动图像放在那里。 - Luciano Brum

5

在我的情况下,只需调整您的图像大小,我的闪屏图像尺寸为1544x2100,所以我改变为1080x2100即可解决问题!希望这能帮到您!!!谢谢!


调整哪些图像以及调整到什么尺寸?是否有任何通用规则可供遵循? - Luciano Brum
你的启动图片不应该太大,你需要调整大小或者移动到xxxhdpi文件夹中。 - Divyaraj

2
尝试在android.view.DisplayListCanvas.throwIfCannotDraw中设置调试点,检查哪些图片会抛出异常。其中一些可能不正确-比如太大或者有太多图片,无法记录到画布池中。

我没有太多的图片,也无法在这个方法上进行调试。 - user7913931
在调试其他方法后,我发现这个位图:android.graphics.bitmap@7od1086 - user7913931
你的图片在_drawable_文件夹里吗?试着移动到_drawable_hdpi_文件夹。这可能会有所帮助。查看此链接:https://dev59.com/s1kT5IYBdhLWcg3wELgl - mzherdev

0
对于仍需要此问题答案的任何人(就像我两天前一样),答案很简单:将所有尺寸大于1024 x 1024的图像调整为1024 x 1024,例如,我有一张图像大约为1080 x 850,这个1080是一个问题,因此需要调整大小并缩小到1024,如果您使用照片编辑工具,在缩放时它会自动设置图像的正确宽度/长度。

0

对于Shuvo Joseph的回答,我有一个补充建议,除了添加drawable-xxhdpi密度文件夹外,还可以添加另一个密度文件夹。
这样无论Android版本和大小如何,您的应用程序都可以准备具有正确尺寸的图像源:

  1. 将顶部左侧的文件夹视图从Android更改为Project
  2. 进入YourProjectFolder文件夹 > app > src > main > res
  3. 使用最佳分辨率准备原始图像,并自动将其拆分为每个文件夹大小。您可以在Baker中完成此操作
  4. 然后创建另一个密度文件夹,即:
  5. drawable-hdpidrawable-ldpidrawable-mdpidrawable-xhdpidrawable-xxhdpidrawable-xxxhdpi
  6. 将每个图像放入相应的文件夹中

0
 private static final int MAX_BITMAP_SIZE = 100 * 1024 * 1024; // 100 MB

    @Override
    protected void throwIfCannotDraw(Bitmap bitmap) {
        super.throwIfCannotDraw(bitmap);
        int bitmapSize = bitmap.getByteCount();
        if (bitmapSize > MAX_BITMAP_SIZE) {
            throw new RuntimeException(
                    "Canvas: trying to draw too large(" + bitmapSize + "bytes) bitmap.");
        }
    }

请查看DisplayListCanvas中的此代码,否则请看View#draw()方法,

boolean draw(Canvas canvas, ViewGroup parent, long drawingTime) {
    boolean drawingWithRenderNode = mAttachInfo != null
                && mAttachInfo.mHardwareAccelerated
                && hardwareAcceleratedCanvas;
    ···
    if (drawingWithRenderNode) {
        // Delay getting the display list until animation-driven alpha values are
        // set up and possibly passed on to the view
        renderNode = updateDisplayListIfDirty();
        if (!renderNode.isValid()) {
            // Uncommon, but possible. If a view is removed from the hierarchy during the call
            // to getDisplayList(), the display list will be marked invalid and we should not
            // try to use it again.
            renderNode = null;
            drawingWithRenderNode = false;
            }
        }
    ···
}

这就是为什么我们可以通过取消硬件加速来解决问题的原因。


1
禁用硬件加速可能会导致其他问题和性能问题,从而影响用户体验和界面。 - Luciano Brum

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