如何在后台线程上加载可绘制对象并在 ReplacementSpan 的绘制方法中将其绘制在 canvas 上?

How to load a drawable on a background thread and draw it on canvas in ReplacementSpan's draw method?

我想在后台线程上从资源加载可绘制对象后操作 canvas。这是代码(相关部分):

public class Test extends ReplacementSpan {
    @Override
    public void draw(
            final Canvas canvas,
            final CharSequence text,
            final int start,
            final int end,
            final float x,
            final int top,
            final int y,
            final int bottom,
            final Paint paint) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                drawable = context.getResources().getDrawable(resourceId);
                drawable.setBounds(0, 0, size, size);

                canvas.save();
                int transY = bottom - size - paint.getFontMetricsInt().descent;
                canvas.translate(x, transY);
                drawable.draw(canvas);
                canvas.restore();
            }
        }).start();
    }
}

此代码导致没有堆栈跟踪的本机崩溃:

Fatal signal 11 (SIGSEGV), code 1, fault addr 0xf8 in tid 10735

我注意到在 canvas 上尝试执行任何类型的操作时会出现崩溃。将在 canvas 上运行的代码放入 new Handler(Looper.getMainLooper()).post(new Runnable() {...}); 并不能解决问题。

如果在主线程上完成,代码工作正常,但在滚动时会导致明显的延迟。

有没有办法在后台线程上加载可绘制对象,然后在 canvas 上绘制它?

尝试使用 runOnMainThread :

public class Test extends ReplacementSpan {
    @Override
    public void draw(
            final Canvas canvas,
            final CharSequence text,
            final int start,
            final int end,
            final float x,
            final int top,
            final int y,
            final int bottom,
            final Paint paint) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                drawable = context.getResources().getDrawable(resourceId);
                drawable.setBounds(0, 0, size, size);
                runOnUiThread(new Runnable() {

                        @Override
                        public void run() {
                            canvas.save();
                            int transY = bottom - size - paint.getFontMetricsInt().descent;
                            canvas.translate(x, transY);
                            drawable.draw(canvas);
                            canvas.restore();
                        }
                    });

            }
        }).start();
    }
}

Is there a way to load the drawable on a background thread and then draw it on canvas?

是的。如果您愿意,可以在后台线程上加载 draw() 之外的可绘制对象。

resourceIdsize 都不是 draw() 的参数。相反,您通过其他方式(构造函数、setter 等)提供这些。此时获取并配置您的可绘制对象,而不是在 draw() 中。这将您的 draw() 工作限制为仅涉及 Canvas.

的语句

顺便说一句,我不是 100% 确定,但如果在您的其他地方使用相同的资源,您可能需要在调用 Drawable 之前调用 mutate(),然后再调用 setBounds()应用