為什麼遊戲需要 Loading 進度條?不是為了好看,而是生存必要。典型 S40 手機 Heap 僅 200KB,幾張 128x128 圖片加聲音、地圖就逼近崩潰邊緣。本文揭示 Loading 界面背後的內存管理邏輯,並給出雙執行緒實現方案。
// 資源加載執行緒
class LoadingThread implements Runnable {
private volatile boolean isLoaded = false;
private int counter = 100; // 模擬進度
public void run() {
while (counter > 0) {
// 真實項目:解碼圖片、載入聲音、解析地圖、初始化對象池
loadNextResource();
counter--;
try { Thread.sleep(20); } catch (Exception e) {}
}
isLoaded = true;
}
public boolean isLoaded() { return isLoaded; }
}
// 主遊戲畫布 (繼承 Canvas/GameCanvas)
class MainCanvas extends Canvas implements Runnable {
private LoadingThread loader;
private Thread renderThread;
private int state = LOADING;
private int loadingCounter = 0;
public MainCanvas() {
loader = new LoadingThread();
new Thread(loader).start(); // 啟動加載執行緒
renderThread = new Thread(this);
renderThread.start(); // 啟動渲染執行緒
}
public void run() { // 渲染迴路
while (true) {
try { Thread.sleep(100); } catch (Exception e) {}
if (loader.isLoaded()) {
loader = null; // 釋放加載器引用
state = GAMING;
}
repaint();
serviceRepaints();
}
}
protected void paint(Graphics g) {
g.setColor(0);
g.fillRect(0, 0, getWidth(), getHeight());
switch (state) {
case LOADING:
g.setColor(0xFFFFFF);
// 動態進度條動畫
g.drawString("LOADING" + ">>>>>".substring(0, loadingCounter),
getWidth() >> 1, getHeight() >> 1, Graphics.HCENTER | Graphics.TOP);
loadingCounter = (loadingCounter + 1) % 5;
break;
case GAMING:
g.setColor(0xFFFFFF);
g.drawString("GAME", getWidth() >> 1, getHeight() >> 1, Graphics.HCENTER | Graphics.TOP);
// 正式遊戲渲染邏輯
break;
}
}
}
isLoaded 保證跨執行緒可見性,無需額外同步開銷。loader = null,幫助 GC 回收加載期臨時對象。loadNextResource() 每幀只處理 1-2 個資源,避免單幀耗時過長導致畫面卡頓。progress 變量 (0-100),渲染執行緒讀取繪製進度條。Loading 界面是 J2ME 遊戲內存管理的「護城河」。雙執行緒協作 + 分批加載 + 及時釋放 + 資源池,四板斧打穿 200KB Heap 限制,讓大型遊戲在功能機上流暢跑起來。