首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> J2ME

J2ME 雙緩衝技術徹底解析:解決畫面閃爍的關鍵模式

     編輯:J2ME

閃爍成因與雙緩衝原理

在 Canvas.paint(Graphics g) 中直接繪製複雜圖形 (多層矩形、文字、圖片疊加) 時,螢幕會逐步顯示繪製過程,造成肉眼可見的閃爍。雙緩衝核心思想:

  1. 建立一個離屏 Image (大小等於螢幕)。
  2. 所有繪圖操作導向該 Image 的 Graphics。
  3. 繪製完成後,一次性 drawImage(offscreen, 0, 0) 複製到螢幕 Graphics。

因螢幕只經歷「空白 → 完整畫面」單一更新,閃爍消失。

平台原生支援檢測

現代手機 (Nokia S40/S60, Sony Ericsson JP-8 等) 多數硬體/驅動層已實作雙緩衝。優先檢測:


if (isDoubleBuffered()) {
    // 直接在 paint(g) 繪製,系統自動處理離屏合成
} else {
    // 需自行實作軟體雙緩衝
}

自行實作軟體雙緩衝範本


public class DoubleBufferCanvas extends Canvas implements CommandListener {
    private Image offscreen;      // 離屏緩衝區
    private int width, height;
    private Command exitCmd = new Command("退出", Command.EXIT, 1);

    public DoubleBufferCanvas() {
        width = getWidth();
        height = getHeight();
        setCommandListener(this);
        addCommand(exitCmd);

        // 僅在系統不支援時建立離屏緩衝區
        if (!isDoubleBuffered()) {
            offscreen = Image.createImage(width, height);
        }
    }

    protected void paint(Graphics g) {
        // 1. 取得實際繪圖目標
        Graphics target = g;
        if (offscreen != null) {
            target = offscreen.getGraphics();
        }

        // 2. 在目標上進行所有繪圖 (複雜邏輯放這裡)
        drawComplexScene(target);

        // 3. 若使用離屏緩衝,一次性複製到螢幕
        if (offscreen != null) {
            g.drawImage(offscreen, 0, 0, Graphics.TOP | Graphics.LEFT);
        }
    }

    private void drawComplexScene(Graphics g) {
        // 範例:繪製巢狀矩形 + 狀態文字
        g.setColor(0xFF8080); // 淺紅
        for (int i = 2, j = 2; i < width/2 - 6 && j < height/2 - 6; i += 2, j += 2) {
            g.drawRect(i, j, width - 2*i, height - 2*j);
        }
        g.setColor(0x000000);
        g.drawString("DoubleBuffered: " + isDoubleBuffered(), width/2, height/2, Graphics.HCENTER | Graphics.TOP);
    }

    public void commandAction(Command c, Displayable d) {
        if (c == exitCmd) {
            // 通知 MIDlet 退出...
        }
    }
}

完整對比測試 MIDlet

以下程式碼可在不支援硬體雙緩衝的舊機型 (如 Nokia 6100, Siemens S55) 上直觀觀察差異:

架構圖

DoubleBufferMIDlet (MIDlet)
    └─ UIController (導航控制器)
         ├─ MainListUI (選單:非雙緩衝 / 雙緩衝)
         ├─ NonDoubleCanvas (無離屏緩衝)
         └─ DoubleCanvas (含離屏緩衝)

關鍵類別實作


// NonDoubleCanvas: 直接在螢幕 Graphics 繪製
public class NonDoubleCanvas extends Canvas implements CommandListener {
    private UIController ctrl;
    public NonDoubleCanvas(UIController ctrl) { this.ctrl = ctrl; addCommand(UIController.BACK_CMD); setCommandListener(this); }
    protected void paint(Graphics g) {
        g.setColor(0x646464);
        for (int i=2,j=2; i

效能與記憶體考量

指標無雙緩衝軟體雙緩衝硬體雙緩衝
閃爍明顯無無
額外 Heap0W × H × 2 bytes (如 240×320 ≈ 150KB)0 (驅動層管理)
CPU 開銷基準+1 次全螢幕 blit極低 (硬體加速)
適用場景簡單 UI、靜態表單遊戲、動畫、複雜圖形、舊機型現代機型預設

最佳實踐建議

  1. 永遠先檢測 isDoubleBuffered(),僅在 false 時配置 offscreen。
  2. 重用 offscreen:不要在 paint 中重複 createImage,在建構子或 sizeChanged 建立一次。
  3. 釋放資源:Canvas 不再顯示時 (如 hideNotify),設 offscreen = null 協助 GC。
  4. 遊戲主迴圈:搭配 Thread.sleep 或 Timer 固定幀率 (如 20fps = 50ms),在 run() 呼叫 repaint() + serviceRepaints()。
  5. 部分更新優化:若只更新小區域,可用 repaint(x,y,w,h) 減少 blit 範圍 (需系統支援)。

小結

雙緩衝是 J2ME 圖形程式設計的基石技能。現代手機多已硬體支援,但理解軟體實作原理、掌握 isDoubleBuffered() 檢測與條件配置模式,能確保應用在全機型上獲得流暢、無閃爍的視覺體驗。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved