J2ME 多媒體 API (MMAPI, JSR 135) 採用 Controller 模式:Player 負責播放,Control 介面提供具體功能 (音量、音調、速率、視訊畫面等)。VolumeControl 是控制音量的標準介面。
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
import javax.microedition.media.*;
public class VolumeControlDemo extends MIDlet implements CommandListener {
private Display display;
private Form form;
private Command cmdExit, cmdIncrease, cmdDecrease;
private Player player;
private VolumeControl volumeControl;
private int volumeLevel = 50; // 0-100
public VolumeControlDemo() {
display = Display.getDisplay(this);
}
protected void startApp() {
// 1. 建立 UI
form = new Form("Volume Control Demo");
cmdExit = new Command("Exit", Command.EXIT, 1);
cmdDecrease = new Command("Volume -", Command.SCREEN, 1);
cmdIncrease = new Command("Volume +", Command.SCREEN, 2);
form.addCommand(cmdExit);
form.addCommand(cmdDecrease);
form.addCommand(cmdIncrease);
form.setCommandListener(this);
display.setCurrent(form);
// 2. 初始化 Player 與 VolumeControl
try {
// 從 JAR 載入音訊資源 (需放在 /res/demo.wav)
player = Manager.createPlayer(getClass().getResourceAsStream("/demo.wav"), "audio/x-wav");
player.setLoopCount(-1); // 無限循環
player.prefetch(); // 預載緩衝
player.start(); // 開始播放
// 3. 從 Player 獲取 VolumeControl
Control[] controls = player.getControls();
for (Control c : controls) {
if (c instanceof VolumeControl) {
volumeControl = (VolumeControl) c;
break;
}
}
if (volumeControl != null) {
volumeControl.setLevel(volumeLevel);
form.append("Initial Volume: " + volumeControl.getLevel());
} else {
form.append("VolumeControl not supported on this device");
}
} catch (Exception e) {
form.append("Error: " + e.getMessage());
e.printStackTrace();
}
}
public void commandAction(Command c, Displayable d) {
if (c == cmdExit) {
try { if (player != null) player.close(); } catch (Exception ignored) {}
notifyDestroyed();
} else if (c == cmdIncrease) {
adjustVolume(10);
} else if (c == cmdDecrease) {
adjustVolume(-10);
}
}
private void adjustVolume(int delta) {
if (volumeControl == null) return;
volumeLevel = Math.max(0, Math.min(100, volumeLevel + delta));
volumeControl.setLevel(volumeLevel);
form.delete(form.size() - 1); // 移除舊音量顯示
form.append("Volume: " + volumeControl.getLevel() + " (setLevel=" + volumeLevel + ")");
}
protected void pauseApp() {
try { if (player != null) player.stop(); } catch (Exception ignored) {}
}
protected void destroyApp(boolean unconditional) {
try { if (player != null) player.close(); } catch (Exception ignored) {}
}
}
| 步驟 | 代碼 | 說明 |
|---|---|---|
| 建立 Player | Manager.createPlayer(InputStream, "audio/x-wav") | 支援格式:WAV、MIDI、AMR、MP3 (視裝置)。JAR 內資源用 getResourceAsStream |
| 預載緩衝 | player.prefetch() | 將資料載入解碼器緩衝,減少播放啟動延遲 |
| 無限循環 | player.setLoopCount(-1) | 背景音樂常用 |
| 獲取 Control | player.getControls() 遍歷檢測 instanceof VolumeControl | Player 可能支援多種 Control:ToneControl、PitchControl、RateControl、VideoControl... |
| 設定音量 | volumeControl.setLevel(0-100) | 0=靜音,100=最大。實際分級數由裝置決定 (可能只有 5-10 級) |
| 讀取音量 | volumeControl.getLevel() | 返回實際設定值 (可能與 setLevel 參數不同) |
| 釋放資源 | player.close() (在 destroyApp/exit) | 釋放原生解碼器、音訊焦點、檔案句柄,必須調用 |
setLevel(33) 可能實際設為 25 或 50VolumeControl 僅影響應用內相對音量pauseApp() 應呼叫 player.stop(),前台恢復 player.start()startApp() 重新 prefetch() + start()Manager.getSupportedContentTypes(null) 獲取裝置支援的 MIME 類型
Gauge volumeGauge = new Gauge("Volume", true, 100, volumeLevel); // 互動式
form.append(volumeGauge);
// 在 commandAction 中同步:
volumeLevel = volumeGauge.getValue();
volumeControl.setLevel(volumeLevel);
比 Command 按鈕更直觀,適合設置介面。
VolumeControl 是 J2ME 音訊控制的核心入口。掌握 Player → Control → VolumeControl 這條鏈路,配合真機音量分級測試、資源釋放規範、背景/前台狀態管理,即可實現穩定、體驗良好的音訊功能。此模式同樣適用於 ToneControl (鍵盤音)、VideoControl (攝像頭/視訊播放畫面)、RecordControl (錄音) 等多媒體擴展。