【问题标题】:SurfaceView appears empty, nothing being renderedSurfaceView 显示为空,未呈现任何内容
【发布时间】:2014-09-04 06:18:39
【问题描述】:

我正在尝试从线程内将一些形状绘制到 SurfaceView 上,但没有任何内容呈现到屏幕上。我看过有同样问题的人提出的类似问题,但没有一个答案能引导我找到解决方案,在我的特定案例中提出了不同的原因。

我创建了一个简化版本的代码来演示这个问题。渲染由 RenderingTestView 类处理,该类实现从 SurfaceView 派生的自定义视图。渲染线程在 RenderingTestView 中实现为 Runnable:

package com.example.renderingtest.app;

import android.content.Context;
import android.graphics.*;
import android.os.Build;
import android.util.AttributeSet;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

public class RenderingTestView extends SurfaceView {
    private SurfaceHolder holder;
    private Paint paint;
    private boolean surfaceCreated = false;
    private Thread videoThread;

    public RenderingTestView(Context context) {
        super(context);
        init_view(context);
    }

    public RenderingTestView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init_view(context);
    }

    public RenderingTestView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init_view(context);
    }

    private void init_view(Context context)
    {
        if (Build.VERSION.SDK_INT >= 11)
            setLayerType(android.view.View.LAYER_TYPE_SOFTWARE, null);

        paint = new Paint();
        paint.setColor(Color.RED);

        holder = getHolder();

        holder.addCallback(new SurfaceHolder.Callback() {
            @Override
            public void surfaceCreated(SurfaceHolder holder) {
                surfaceCreated = true;

                videoThread = new Thread(videoRunnable);
                videoThread.start();
            }

            @Override
            public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
                // do nothing
            }

            @Override
            public void surfaceDestroyed(SurfaceHolder holder) {
                surfaceCreated = false;
            }
        });
    }

    private Runnable videoRunnable = new Runnable() {
        @Override
        public void run() {
            Thread.currentThread().setPriority(Thread.NORM_PRIORITY);

            while (true) {
                if (!surfaceCreated || !holder.getSurface().isValid())
                    continue;

                Canvas c = holder.lockCanvas(null);
                try {
                    synchronized (holder) {
                        if (c != null)
                            Draw(c);
                    }
                }
                finally {
                    if (c != null)
                        holder.unlockCanvasAndPost(c);
                }
            }
        }
    };

    protected void Draw(Canvas canvas)
    {
        canvas.drawCircle(0, 0, 100, paint);
    }
}

Draw() 中放置一个断点确认它被成功调用。

布局文件如下所示:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingBottom="@dimen/activity_vertical_margin"
    tools:context="com.example.renderingtest.app.RenderingTest" android:background="#000000">

    <com.example.renderingtest.app.RenderingTest
            android:id="@+id/renderingTestView"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_alignParentRight="true"
            android:layout_alignParentEnd="true" android:layout_alignParentTop="true"/>

</RelativeLayout>

RenderingTestView 中覆盖onDraw(),如下所示:

@Override
public void onDraw(Canvas canvas)
{
     super.onDraw(canvas);
     Draw(canvas);
}

... 并在 init_view() 内调用 setWillNotDraw(false) 实际上会产生所需的输出,但我想从 Runnable 内部进行渲染,而不是等待 invalidate() 产生对 onDraw() 的调用。

【问题讨论】:

  • 很难想象你在做什么以及为什么会出错。请理解 SurfaceView 与其他 View 不同——它有一个 View 部分和一个 Surface 部分。 View 部分是用于布局目的的透明占位符,应该被忽略。 Surface 是一个完全独立的层,绘制在所有 UI 元素的后面(除非您使用 SurfaceHolder API 更改 Z 顺序)。检查您的布局并确保您没有将视图部分清除为不透明的颜色。
  • 我正在做的是将形状渲染到 SurfaceView 的画布上。问题是我发布的确切代码没有在画布上绘制任何东西,而实际上它应该。无论如何,我终于找到了原因,并将发布答案。

标签: java android multithreading graphics surfaceview


【解决方案1】:

经过进一步测试,我发现问题是由以下代码引起的:

if (Build.VERSION.SDK_INT >= 11)
    setLayerType(android.view.View.LAYER_TYPE_SOFTWARE, null);

事实证明,如上所述调用setLayerType() 会以某种方式阻止SurfaceView 将任何内容渲染到Canvas 上,并且无论如何都是不必要的,因为SurfaceView 渲染总是在软件中执行。在第一次测试我的绘图调用时,我使用的是常规的 View 而不是 SurfaceView,并且有问题的行是从那里继承下来的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-20
    • 1970-01-01
    • 2011-09-07
    • 2021-08-10
    • 2017-08-10
    • 1970-01-01
    相关资源
    最近更新 更多