2014-09-04 112 views
0

我想從一個線程內將一些圖形繪製到SurfaceView上,但是沒有任何東西正在呈現給屏幕。我曾經看過類似的問題,但有同樣的問題,但沒有一個答案讓我找到了解決方案,這表明我的具體情況有其他原因。SurfaceView顯示爲空,沒有顯示任何東西

我創建了一個簡化版本的代碼來演示問題。渲染由RenderingTestView類處理,該類實現了從SurfaceView派生的自定義視圖。渲染線程實現爲一個Runnable內RenderingTestView:

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> 

重寫onDraw()RenderingTestView,像這樣:

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

...並呼籲setWillNotDraw(false)init_view()事實上確實產生所需的輸出,但我想從Runnable內部進行渲染,而不是等待invalidate()調用onDraw()

+0

很難描繪你在做什麼以及爲什麼會出錯。理解SurfaceView與其他Views不同 - 它具有View部分和Surface部分。視圖部分是一個用於佈局目的的透明佔位符,應該被忽略。 Surface是在所有UI元素後面繪製的完全獨立的圖層(除非使用SurfaceHolder API更改Z順序)。檢查你的佈局,並確保你沒有將視圖部分清除爲不透明的顏色。 – fadden 2014-09-04 15:38:43

+0

我正在做的是將圖形渲染到SurfaceView的畫布上。問題是我發佈的確切代碼並沒有在畫布上繪製任何東西,實際上它應該是這樣。無論如何,我終於找到了原因,並會發布答案。 – 2014-09-04 17:55:41

回答

1

進一步測試後,我發現這個問題是由下面的代碼引起的:

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

原來叫setLayerType()如上某種程度上防止SurfaceView從渲染任何東西到Canvas,並且在任何情況下,不需要,因爲SurfaceView渲染總是在軟件中執行。當第一次測試我的平局電話時,我使用的是常規的View而不是SurfaceView,並且違規線路從那裏繼續。