In Android, se si desidera animare un oggetto e farlo spostare un oggetto da posizione1 a posizione2, l'API di animazione individua le posizioni intermedie (interpolazione) e quindi mette in coda sul thread principale le operazioni di spostamento appropriate nei momenti appropriati utilizzando un timer . Funziona bene, tranne per il fatto che il thread principale viene solitamente utilizzato per molte altre cose: disegnare, aprire file, rispondere agli input dell'utente, ecc. Un timer in coda può spesso essere ritardato. Programmi ben scritti cercheranno sempre di eseguire il maggior numero possibile di operazioni nei thread in background (non principali), tuttavia non è sempre possibile evitare di utilizzare il thread principale. Le operazioni che richiedono di operare su un oggetto UI devono sempre essere eseguite sul thread principale. Inoltre, molte API restituiranno le operazioni al thread principale come una forma di sicurezza del thread.
Le viste sono tutte disegnate sullo stesso thread della GUI che viene utilizzato anche per tutte le interazioni dell'utente.
Pertanto, se è necessario aggiornare la GUI rapidamente o se il rendering richiede troppo tempo e influisce sull'esperienza utente, utilizzare SurfaceView.
Esempio di immagine di rotazione:
public class MySurfaceView extends SurfaceView implements SurfaceHolder.Callback {
private DrawThread drawThread;
public MySurfaceView(Context context) {
super(context);
getHolder().addCallback(this);
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
drawThread = new DrawThread(getHolder(), getResources());
drawThread.setRunning(true);
drawThread.start();
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
boolean retry = true;
drawThread.setRunning(false);
while (retry) {
try {
drawThread.join();
retry = false;
} catch (InterruptedException e) {
}
}
}
}
class DrawThread extends Thread{
private boolean runFlag = false;
private SurfaceHolder surfaceHolder;
private Bitmap picture;
private Matrix matrix;
private long prevTime;
public DrawThread(SurfaceHolder surfaceHolder, Resources resources){
this.surfaceHolder = surfaceHolder;
picture = BitmapFactory.decodeResource(resources, R.drawable.icon);
matrix = new Matrix();
matrix.postScale(3.0f, 3.0f);
matrix.postTranslate(100.0f, 100.0f);
prevTime = System.currentTimeMillis();
}
public void setRunning(boolean run) {
runFlag = run;
}
@Override
public void run() {
Canvas canvas;
while (runFlag) {
long now = System.currentTimeMillis();
long elapsedTime = now - prevTime;
if (elapsedTime > 30){
prevTime = now;
matrix.preRotate(2.0f, picture.getWidth() / 2, picture.getHeight() / 2);
}
canvas = null;
try {
canvas = surfaceHolder.lockCanvas(null);
synchronized (surfaceHolder) {
canvas.drawColor(Color.BLACK);
canvas.drawBitmap(picture, matrix, null);
}
}
finally {
if (canvas != null) {
surfaceHolder.unlockCanvasAndPost(canvas);
}
}
}
}
}
attività:
public class SurfaceViewActivity extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new MySurfaceView(this));
}
}