WMS:Exibição de desenho do SurfaceView
1. Uso do controle SurfaceView
1.1 Coreógrafo aceita sinal VSync
Choreographer é um canal fornecido pelo Android para obter sinais VSync. O controle aqui
SurfaceView
desenha ativamente na tela e, em aplicativos gerais como o
Choreographer no WMS, ao adicionar uma interface com o sinal de interrupção VSYNC, ele inicia a partir do método scheduleTraversals do ViewRootImpl e adiciona internamente a tarefa de desenho ao Choreographer por meio do postCallback do Choreographer.
Choreographer.getInstance().postFrameCallback(new Choreographer.FrameCallback() {
@Override
public void doFrame(long frameTimeNanos) {
//当vsync信号来时会调用到这里
mHandler.sendEmptyMessage(MyHandler.TAG_UPDATE_TEXT);
Choreographer.getInstance().removeFrameCallback(this);
Choreographer.getInstance().postFrameCallback(this);
}
});
1.2 SurfaceView personalizado
MySurfaceView
Coloque-o no construtormSurfaceHolder = this.getHolder()
e configure-oSurfaceHolder.Callback
- Herdar
Runnable
,Thread
executar eGlobal.syncCondition.await();
aguardar aqui a mensagem de notificação da chegada do vsync- Processamento simultâneo de thread
Lock
eCondition
:public class Global { public static ReentrantLock lock = new ReentrantLock(); public static Condition syncCondition = lock.newCondition(); private Global() { } }
Choreographer#doFrame
NotificarGlobal.syncCondition.signal();
outro tópico para atualizar a tela
com/xhbruce/ui/MySurfaceView.java
public class MySurfaceView extends SurfaceView implements SurfaceHolder.Callback, Runnable {
private static String TAG = "MySurfaceView";
private SurfaceHolder mSurfaceHolder;
private int autoNum = 0;
private Paint mPaint = new Paint();
public MySurfaceView(Context context) {
this(context, null);
}
public MySurfaceView(Context context, AttributeSet attrs) {
this(context, attrs , 0);
}
public MySurfaceView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mSurfaceHolder = this.getHolder();
mSurfaceHolder.addCallback(this);
Log.d(TAG, "MySurfaceView(3) holder=" + mSurfaceHolder.toString());
}
public MySurfaceView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
mSurfaceHolder = this.getHolder();
mSurfaceHolder.addCallback(this);
Log.d(TAG, "MySurfaceView(4) holder=" + mSurfaceHolder.toString());
}
@Override
public void surfaceCreated(@NonNull SurfaceHolder holder) {
Log.d(TAG, "surfaceCreated() holder=" + holder.toString());
new Thread(this).start();
// draw();//画蓝色或绿色
}
@Override
public void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width, int height) {
}
@Override
public void surfaceDestroyed(@NonNull SurfaceHolder holder) {
}
@Override
public void run() {
while (true) {
Log.d(TAG, "run() autoNum=" + autoNum);
Global.lock.lock();
try {
Global.syncCondition.await();//在这里等待vsync到来的通知消息
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
Global.lock.unlock();
}
draw();//画蓝色或绿色
}
}
private void draw() {
Canvas mCanvas = null;
try {
mCanvas = mSurfaceHolder.lockCanvas();
if (autoNum % 2 == 0) {
mPaint.setColor(Color.BLUE);//如果为双数则画面画成蓝色
} else {
mPaint.setColor(Color.GREEN);//如果为单数则画面画成绿色
}
mCanvas.drawRect(0, 0, getRight(), getBottom(), mPaint);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (mCanvas != null) {
mSurfaceHolder.unlockCanvasAndPost(mCanvas);
}
}
Log.d(TAG, "draw() autoNum=" + autoNum);
autoNum++;//数字加1
}
}
Arquivos de atividade e layout xml correspondentes:
com/xhbruce/surfaceviewtest/MySurfaceViewTest.java
public class MySurfaceViewTest extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my_surface_view_test);
Choreographer.getInstance().postFrameCallback(new Choreographer.FrameCallback() {
@Override
public void doFrame(long frameTimeNanos) {
//当vsync信号来时会调用到这里
Global.lock.lock();
try {
Global.syncCondition.signal();//通知另一条线程更新画面
} catch (Exception e) {
e.printStackTrace();
} finally {
Global.lock.unlock();
}
Choreographer.getInstance().removeFrameCallback(this);
Choreographer.getInstance().postFrameCallback(this);
}
});
}
}
layout/atividade_minha_superfície_view_test.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MySurfaceViewTest">
<com.xhbruce.ui.MySurfaceView
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
1.3 Resultados
Demonstração do SurfaceView
2. SurfaceView obtém a tela e a exibe
- SurfaceHolder.lockCanvas() obtém o objeto Canvas e bloqueia a tela
- SurfaceHolder.unlockCanvasAndPost(Canvas canvas) encerra o desenho bloqueado, envia as alterações e exibe os gráficos.
2.1 SurfaceHolder.lockCanvas()
A função finalmente chamada pelo método lock do Surface
GraphicBufferProducer
obtémdequeueBuffer
um Slot. Se o Slot não tiver um GraphicBuffer alocado, será alocado um GraphicBuffer neste momento e, em seguida, um sinalizador com uma marca será retornado.BUFFER_NEEDS_REALLOCATION
Depois que o lado do aplicativo vir este sinalizador , ele passará as interfaces requestBuffer e importBuffer.Mapeie GraphicBuffer para seu próprio espaço de processo.
2.2 SurfaceHolder.unlockCanvasAndPost (tela de tela)
SurfaceView usa dois Canvas, one
frontCanvas
e onebackCanvas
, ao atualizar a visualização. O frontCanvas é exibido a cada vez, e o backCanvas armazena a visualização antes da última alteração. Ao usar lockCanvas() para obter a tela, o que você obtém é, na verdade, backCanvas. do frontCanvas exibido. Em seguida, você desenha uma nova visualização no backCanvas obtido e, em seguida,unlockCanvasAndPost(Canvas canvas)
esta visualização, a tela carregada substituirá o frontCanvas original como o novo frontCanvas, e o frontCanvas original mudará para o plano de fundo como backCanvas.