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

J2ME paint() 優化完全指南:從模擬器流暢到真機不卡的六大鐵律

     編輯:J2ME

現象:模擬器 60fps,真機 5fps 甚至白屏

根因:**真機 GPU/CPU 極弱、無硬件加速、GC 停頓敏感、記憶體碎片嚴重**。paint() 為渲染熱點,**任何低效操作被放大數十倍**。

六大優化鐵律

1. 絕不在 paint() 中做 I/O 或 new 物件


// ❌ 災難寫法:每幀讀取圖片、創建對象
public void paint(Graphics g) {
    try {
        Image bg = Image.createImage("/back.png");  // IO + 解碼 + 內存分配
        g.drawImage(bg, 0, 0, Graphics.TOP | Graphics.LEFT);
    } catch (Exception e) {}
}

// ✅ 正確:預載入,paint 僅引用
private Image bgImage;
public void init() {  // 或構造器
    try { bgImage = Image.createImage("/back.png"); } catch (Exception e) {}
}
public void paint(Graphics g) {
    g.drawImage(bgImage, 0, 0, Graphics.TOP | Graphics.LEFT);
}

2. 使用低色深、小尺寸圖片

  • 優先 **8-bit PNG (256 色)** 或 **16-bit (RGB565)**,避免 24/32-bit
  • 圖片尺寸**不超過螢幕分辨率**;大圖切片、九宮格拉伸
  • 漸變/陰影用**程序繪製**(drawLine 漸變)替代大圖
  • 工具:pngcrush -brute、ImageOptim 無損壓縮

3. 局部重繪


// 方式一:repaint(x,y,w,h) —— 內部自動設置 clip
repaint(10, 10, 50, 30);  // 僅重繪 50x30 區域

// 方式二:手動 clip(更精確控制)
public void paint(Graphics g) {
    g.setClip(10, 10, 50, 30);
    // 僅繪製變化區域
    g.drawImage(dirtyImage, 10, 10, Graphics.TOP | Graphics.LEFT);
    // 其餘區域保持不變(雙緩衝自動保留)
}

原理:Graphics 維護一個**裁剪矩形**,像素操作僅影響矩形內部。

4. 減少 repaint() 調用頻率

  • **臟標記模式**:邏輯線程設置 dirty = true,渲染幀檢查後重置
  • 靜態畫面(菜單、暫停)**完全不調用 repaint**
  • 動畫幀率鎖定:Thread.sleep(1000/目標FPS)

5. 將計算移出 paint()


// ❌ paint 中計算座標、字符串拼接
public void paint(Graphics g) {
    String msg = "Score: " + score + " Level: " + level;  // new String 每幀
    int x = (getWidth() - g.getFont().stringWidth(msg)) / 2;
    g.drawString(msg, x, 10, Graphics.TOP | Graphics.LEFT);
}

// ✅ 邏輯線程預計算,paint 僅繪製
private String scoreStr;
private int scoreX;
private boolean uiDirty;

public void updateUI() {  // 邏輯線程調用,僅分數變化時
    scoreStr = "Score: " + score + " Level: " + level;
    scoreX = (width - font.stringWidth(scoreStr)) / 2;
    uiDirty = true;
}

public void paint(Graphics g) {
    if (uiDirty) {
        g.drawString(scoreStr, scoreX, 10, Graphics.TOP | Graphics.LEFT);
        uiDirty = false;
    }
}

6. 雙緩衝技術


// 檢測設備支援
boolean hwDoubleBuffered = isDoubleBuffered();  // Canvas 方法

// 軟件雙緩衝(通用)
private Image offscreen;
private Graphics offG;

public void init() {
    offscreen = Image.createImage(getWidth(), getHeight());  // 可變圖像
    offG = offscreen.getGraphics();
}

public void renderFrame() {  // 邏輯線程調用
    // 1. 所有繪製操作導向 offG
    offG.setColor(0x000000);
    offG.fillRect(0, 0, getWidth(), getHeight());
    drawGame(offG);
    // 2. paint 僅一行:將離屏圖像貼到屏幕
}

public void paint(Graphics g) {
    g.drawImage(offscreen, 0, 0, Graphics.TOP | Graphics.LEFT);
}

優勢:**paint() 極簡、零計算、零 new、零 clip 變更**,繪製延遲穩定在 1-2ms。

綜合優化檢查表

檢查項工具/方法目標
paint() 分配對象代碼審查 / 輕量級 Profiler0 次/幀
Image createImage 調用同上0 次/幀
字符串拼接同上0 次/幀
完整屏幕重繪比例日誌統計< 20%
幀耗時 (真機)System.currentTimeMillis() 埋點< 16ms (60fps) / < 33ms (30fps)
GC 頻率VM 參數 -verbose:gc / 真機日誌無全局 GC / 幀間無 GC

結語

paint() 優化本質是**將「計算」與「繪製」徹底分離、將「變」與「不變」徹底隔離**。遵循六大鐵律、建立自動化檢查機制,即可讓同一份代碼在模擬器與真機上**同樣流暢**,消除「模擬器騙我」的痛苦。

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