Android decodeByteArray 在自己的线程上非常慢,但在 UI 线程上不是

Android decodeByteArray very slow on own Thread but not on UI Thread

我实际上正在从事一个基于相机的项目。我正在添加一个队列,从 onPreviewFrame 中预览来自相机的帧,我在 运行 线程中返回以处理并在 SurfaceView 中绘制它。 (我的目标是通过网络发送)。

我的问题是 BitmapFactory.decodeByteArray() 函数在我的自定义线程上非常慢,但在 UI 线程 上工作得很好:

这很好用:

    private void drawFromThread(final byte[] data) {

    size = mCamera.getPreviewSize();
    YuvImage yuvimage;
    yuvimage = new YuvImage(data, ImageFormat.NV21, size.width,size.height, null);
    ByteArrayOutputStream baos;
    baos = new ByteArrayOutputStream();
    yuvimage.compressToJpeg(new Rect(0, 0, size.width, size.height), 10,baos);  
    final byte[] jdata = baos.toByteArray();
    ((Activity)context).runOnUiThread(new Runnable(){
        @Override
        public void run() {
            Bitmap bmp;
            bmp = BitmapFactory.decodeByteArray(jdata, 0, jdata.length);
            Canvas canvas = contactView.getHolder().lockCanvas();
            canvas.drawBitmap(bmp, 0, 0, null);
            contactView.getHolder().unlockCanvasAndPost(canvas);
        }
    });
}

但是这个,真的很慢:

    private void drawFromThread(final byte[] data) {

    size = mCamera.getPreviewSize();
    YuvImage yuvimage;
    yuvimage = new YuvImage(data, ImageFormat.NV21, size.width,
            size.height, null);
    ByteArrayOutputStream baos;
    baos = new ByteArrayOutputStream();
    yuvimage.compressToJpeg(new Rect(0, 0, size.width, size.height), 10,
            baos);
    final byte[] jdata = baos.toByteArray();
    Bitmap bmp;
    bmp = BitmapFactory.decodeByteArray(jdata, 0, jdata.length);
    Canvas canvas = contactView.getHolder().lockCanvas();
    canvas.drawBitmap(bmp, 0, 0, null);
    contactView.getHolder().unlockCanvasAndPost(canvas);
}

我用谷歌搜索了很多,但没有找到有同样问题的人。

我知道有最有效的方法来使用相机和 SurfaceView,我有另一个 surfaceView 用于在 "standard way" 中显示我的相机帧。但我正在尝试模拟从网络获取的帧并将其绘制在 SurfaceView 上。

感谢您的宝贵时间。

我认为它看起来很慢,因为在这个慢示例中,您实际上没有在 UI 线程上执行任何操作。有可能 canvas 由于其他原因 运行 更新而稍后更新。相反,如果您在一个线程中进行计算,然后在 UI 中呈现它,它应该有更快的响应时间。

private void drawFromThread(final byte[] data) {

    size = mCamera.getPreviewSize();
    YuvImage yuvimage;
    yuvimage = new YuvImage(data, ImageFormat.NV21, size.width,size.height, null);
    ByteArrayOutputStream baos;
    baos = new ByteArrayOutputStream();
    yuvimage.compressToJpeg(new Rect(0, 0, size.width, size.height), 10,baos);  
    final byte[] jdata = baos.toByteArray();

    final Bitmap bmp = BitmapFactory.decodeByteArray(jdata, 0, jdata.length);
    ((Activity)context).runOnUiThread(new Runnable(){
        @Override
        public void run() {
            Canvas canvas = contactView.getHolder().lockCanvas();
            canvas.drawBitmap(bmp, 0, 0, null);
            contactView.getHolder().unlockCanvasAndPost(canvas);
        }
    });
}

请注意,"expensive" decodeByteArray 是在 UI 线程中完成的,但渲染是在 UI 线程中完成的。不行吗?

我找到了问题的根源。我正在从 Ui 线程中将我的相机预览帧推入队列。我在另一个线程上从队列中检索的帧。问题是 Ui 线程每秒在队列中推送的帧数超过了另一个线程每秒可以处理的帧数。在 Ui 线程上执行 decodeByteArray 会减慢它的速度,这可以让其他线程有时间绘制我的位图。 我改变了我正在使用的队列类型以使其更快,并且仍然试图找到一种在我的线程中更快渲染的方法。 如果有人有建议,我会采纳。