2010-08-26 2 views
6

Я пытаюсь выяснить, как обойти мою проблему. Я читал http://groups.google.com/group/android-developers/browse_thread/thread/a2aac88a08cb56c2/b7dff4ba388cd664?lnk=gst&q=SurfaceView#b7dff4ba388cd664, который отвечает на мой вопрос, но насколько я могу судить, это своего рода ответ «удачи». Итак, вот моя проблема:SurfaceView мерцающий/разрывающий

Я использую SurfaceView обычным способом (lock/unlockAndPost), чтобы рисовать растровое изображение моего игрового фона всякий раз, когда поверхность изменяется (например, ориентация и т. Д.), И я представляю серию движущихся кругов (до 30 с радиусом около 25.f). Данные x, y для позиций этих кругов поступают с сервера и все работает нормально. Все объекты окружения хранятся в списке, и их положение обновляется, чтобы обеспечить синхронизацию этого обновления. Однако, когда я рисую эти круги на экране (во время canvas.lock()), большую часть времени они визуализируют прекрасный, но иногда (например, раз в несколько секунд) некоторые из кругов, похоже, краснеют или мерцают для кадра. Количество кругов всегда постоянное, так что это не проблема, и нет никаких параллельных изменений в списке кругов (как я уже сказал, он синхронизирован). Я даже попробовал рисовать все эти круги в растровое изображение каждого цикла рендеринга и рисовать это растровое изображение на основном холсте. Это, похоже, еще больше влияет на производительность (~ 13FPS в отличие от ~ 30FPS при рисовании кругов непосредственно на основной холст). Извините, если информация немного расплывчата, (стараюсь держать компанию счастливой: p), но мне просто интересно, может ли кто-нибудь дать мне ключ? Или мне просто не повезло. Следует отметить, что данные позиционирования, поступающие с сервера, являются данными в реальном времени, и жизненно важно, чтобы рендеринг отражал эти позиции в реальном времени.

Спасибо за помощь! Chris

EDIT:

Справедливо. Вот run() из потока рендеринга.

@Override 
    public void run() { 
     Canvas c; 
     while (mRun) { 
      c = null; 
      try { 
       c = mSurfaceHolder.lockCanvas(null); 
       synchronized (mSurfaceHolder) { 
        panel.onDraw(c); 
       } 
      } finally { 
       if (c != null) { 
        mSurfaceHolder.unlockCanvasAndPost(c); 
       } 
      } 
     } 
    } 

Довольно стандартный материал (почти калька лунного посадочного модуля: р)

@Override 
public void surfaceCreated(SurfaceHolder holder) { 
    mBackground= Bitmap.createBitmap(this.getWidth(), this.getHeight(), Bitmap.Config.RGB_565); 
    screenOrientation = getResources().getConfiguration().orientation; 
    if(thread.getState()== Thread.State.TERMINATED){ 
     thread = new RenderThread(holder, this); 
     thread.setRunning(true); 
     thread.start(); 
    }else { 
     thread.setRunning(true); 
     thread.start(); 
    } 
} 



@Override 
public void surfaceChanged(SurfaceHolder holder, int format, int width, 
     int height) { 
    Canvas c = new Canvas(mField); 
    c.drawARGB(255,0,144,0); 
    backgroundDetails.renderOnPanel(c, this); 
    screenOrientation = getResources().getConfiguration().orientation; 
} 

Довольно легко следовать, просто перерисовывать фоновое изображение при изменении ориентации и начать рендеринг нить.

public void onDraw(Canvas canvas) { 
    canvas.drawBitmap(mField,0,0,null); 
    drawPositionBeans(canvas, this); 
} 

И наконец:

public void onDraw(Canvas canvas, RadarView radarView) { 
    float beanX=0, beanY=0; 
    float radius = 25.0f; 
    final List<PositionBean> copyOfList = Collections.synchronizedList(positionBeans.getPositionBeans()); 
    synchronized(copyOfList){ 
     try { 
      for (final PositionBean pb : copyOfList) 
      { 
       if (panel.getOrientation() == Configuration.ORIENTATION_PORTRAIT) { 
        beanX = (float)pb.getY()*(-1); 
        beanY = (float)pb.getX(); 
       } else { 
        beanX = (float)pb.getY()*(-1); 
        beanY = (float)pb.getX()*(-1); 
       } 
       mPaint.setARGB(255,pb.getRgbColor().getR(), pb.getRgbColor().getG(), pb.getRgbColor().getB()); 
       panel.drawSpot(canvas, beanX, beanY, radius, mPaint); 

       mPaint.setStyle(Paint.Style.STROKE); 
       mPaint.setARGB(255,255,222,1); 
       for (int j = 0; j < selectedBean.size(); ++j) 
       { 
        if(pb.getTrack()==selectedBean.get(j)) { 
         panel.drawSpot(canvas, beanX, beanY, radius+1, mPaint); 
        } 
       } 
       mPaint.setStyle(Paint.Style.FILL); 
      } 

     } catch(Exception e) { 
      Log.e("render", "Exception Drawing Beans: " + e); 
     } 
    } 
} 

Еще раз спасибо, ребята. Chris

+0

невозможно ответить, не видя ваш gameloop и рисунок кода. – Sebi

+0

То же, что сказал Себи - образец кода был бы полезен - но считаете ли вы, что позиции, которые вы получаете иногда, неверны? Просто мысль о том, почему круги могут «мерцать», если они временно закрыты для просмотра. Опять же, без какого-либо кода это будет невозможно ответить. – Seidr

+0

Большое спасибо за помощь ребятам. Но да, я уверен, что данные позиционирования верны. –

ответ

0

У меня была эта проблема. Решение, подходящее для меня, - это синхронизация метода и метода onDraw, который обновляет матрицу трансформации. Потому что были рамки, когда матрица идентична (начальное значение новой матрицы()), а в следующем фрейме имели правильные значения.

1

Это происходит потому, что графика Android имеет поверхность буфера и видимую поверхность, и чтобы они всегда были доступны, они просто чередуются. Это означает, что если вы нарисуете один кадр, он не будет рядом, если вы не нарисуете его на каждом кадре.

http://groups.google.com/group/android-developers/msg/8d1243c33f9b7b6e?pli=1

0

я нашли после прочтения немного о целях поверхности, что, если вы звоните

getHolder().lockCanvas(); 

Вы должны сделать все, еще раз.

Если вы не предоставите свою грязную территорию.

getHolder().lockCanvas(Rect dirty); 

Если вы хотите, чтобы перерисовать область, определенную в Rect