在 Android 開(kāi)發(fā)中,View 和 SurfaceView 是兩種常用的視圖繪制組件。它們雖然都能用于繪制內(nèi)容,但其更新機(jī)制不同,分別適用于不同的場(chǎng)景。理解它們的區(qū)別,有助于在開(kāi)發(fā)中選擇合適的組件。
View 是 Android 中最常見(jiàn)的 UI 組件,它的繪制過(guò)程由系統(tǒng)的主線程(UI 線程)管理。通常情況下,View 只有在需要時(shí)才會(huì)刷新,比如當(dāng)我們調(diào)用 invalidate() 方法時(shí),系統(tǒng)會(huì)在下一次繪制周期內(nèi)更新視圖。這種機(jī)制被稱為主動(dòng)更新,因?yàn)殚_(kāi)發(fā)者需要顯式請(qǐng)求視圖更新。
示例:
假設(shè)有一個(gè)按鈕,點(diǎn)擊按鈕后改變其背景顏色。此時(shí)可以在 onClick() 方法中調(diào)用 invalidate() 來(lái)觸發(fā)更新。系統(tǒng)將會(huì)在下一個(gè)繪制周期重新繪制這個(gè)按鈕。
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
button.setBackgroundColor(Color.RED);
button.invalidate(); // 主動(dòng)請(qǐng)求重新繪制
}
});
總結(jié):
View 適用于不需要頻繁刷新的場(chǎng)景,通過(guò)事件觸發(fā)或手動(dòng)調(diào)用 invalidate(),系統(tǒng)會(huì)在下一次繪制周期中進(jìn)行更新。典型應(yīng)用場(chǎng)景包括用戶交互驅(qū)動(dòng)的 UI 更新,如點(diǎn)擊按鈕、滑動(dòng)手勢(shì)等。
2. SurfaceView:適用被動(dòng)更新,頻繁刷新
SurfaceView 則是另一種更適合高頻率繪制任務(wù)的組件。與 View 不同,SurfaceView 擁有自己的獨(dú)立繪制線程,通常在子線程中進(jìn)行復(fù)雜的繪制操作。這意味著 SurfaceView 能夠在主線程之外進(jìn)行繪制,并且支持更頻繁的內(nèi)容更新。被動(dòng)更新 指的是通過(guò)持續(xù)的刷新循環(huán)更新視圖內(nèi)容,適合用于高幀率動(dòng)畫、游戲渲染、視頻播放等場(chǎng)景。
示例:
在游戲場(chǎng)景中,角色的移動(dòng)和場(chǎng)景的動(dòng)畫需要頻繁更新。這時(shí)可以使用 SurfaceView 并在獨(dú)立的線程中不斷刷新屏幕。
class GameSurfaceView extends SurfaceView implements SurfaceHolder.Callback {
private GameThread gameThread;
public GameSurfaceView(Context context) {
super(context);
getHolder().addCallback(this);
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
gameThread = new GameThread(holder);
gameThread.setRunning(true);
gameThread.start();
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
boolean retry = true;
gameThread.setRunning(false);
while (retry) {
try {
gameThread.join();
retry = false;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class GameThread extends Thread {
private SurfaceHolder surfaceHolder;
private boolean running;
public GameThread(SurfaceHolder surfaceHolder) {
this.surfaceHolder = surfaceHolder;
}
public void setRunning(boolean running) {
this.running = running;
}
@Override
public void run() {
while (running) {
Canvas canvas = null;
try {
canvas = surfaceHolder.lockCanvas();
synchronized (surfaceHolder) {
// 執(zhí)行頻繁的繪制操作
canvas.drawColor(Color.BLACK); // 清空畫布
// 其他繪制操作...
}
} finally {
if (canvas != null) {
surfaceHolder.unlockCanvasAndPost(canvas);
}
}
}
}
}
}
總結(jié):
SurfaceView 適用于需要頻繁刷新和復(fù)雜渲染的場(chǎng)景。它通過(guò)獨(dú)立線程進(jìn)行渲染,避免了主線程的阻塞,特別適合游戲、視頻播放或需要高幀率更新的場(chǎng)景。
3. 主動(dòng)更新 vs 被動(dòng)更新 總結(jié)
-
View 的主動(dòng)更新:適合不頻繁更新的操作,如按鈕點(diǎn)擊、UI 交互。這些更新通過(guò)
invalidate()請(qǐng)求,由系統(tǒng)在下一個(gè)繪制周期進(jìn)行處理。適合大部分 UI 控件的場(chǎng)景。 - SurfaceView 的被動(dòng)更新:適用于高頻更新的場(chǎng)景,通過(guò)子線程不斷進(jìn)行繪制,適合游戲渲染、視頻播放等需要持續(xù)、頻繁更新的場(chǎng)景。