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

UniJa 平台 MIDI 音效播放優化:單線程模式避免死機、資源釋放與循環播放最佳實踐

     編輯:J2ME

問題背景

UniJa (聯想 Java 平台) 在 MIDP 2.0 javax.microedition.media.Player 基礎上封裝音頻播放。開發早期採用「每次播放開新線程」模式,導致長時間運行 (5-6 小時) 後 CPU 調度開銷累積,出現「死機」現象。本文分析根因,提出單線程複用 Player 的穩健方案。

方案對比

❌ 多線程模式 (不推薦)

// 每次播放創建新線程
new Thread() {
    public void run() {
        snd.playMIDI("/a.mid");
    }
}.start();

// 停止時銷毀對象
if (snd != null) snd.destroy(); // 釋放為 null,下次需 new SoundEffects()

缺點:線程創建/銷毀頻繁 → CPU 調度壓力大 → 長時間運行資源洩漏 → 系統假死。

✅ 單線程複用模式 (推薦)

核心原則:應用全生命周期僅維護 一個 Player 實例,播放新音效前 close() 釋放舊資源,再 createPlayer() 載入新數據。

SoundEffects 核心類實現 (修正版)

package fancy.test;

import javax.microedition.media.*;
import javax.microedition.media.control.VolumeControl;
import java.io.*;

public class SoundEffects {
    private String filename;
    private String contentType;  // audio/midi, audio/x-wav, audio/basic, audio/mpeg, audio/x-tone-seq
    private int loopCount;       // 循環次數,1_000_000 模擬無限循環
    private Player player;
    private InputStream is;

    public SoundEffects(int loopCount) {
        this.loopCount = loopCount;
    }

    // 統一播放入口
    public void playMIDI(String filename) { playSound(filename, "audio/midi"); }
    public void playWAV(String filename)  { playSound(filename, "audio/x-wav"); }
    public void playAU(String filename)   { playSound(filename, "audio/basic"); }
    public void playMP3(String filename)  { playSound(filename, "audio/mpeg"); }
    public void playTone(String filename) { playSound(filename, "audio/x-tone-seq"); }

    protected synchronized void playSound(String filename, String contentType) {
        close();                    // 1. 釋放舊 Player
        this.filename = filename;
        this.contentType = contentType;
        playFile();                 // 2. 載入並播放新音頻
    }

    // 釋放所有資源
    protected void close() {
        if (player != null) {
            player.close();
            player = null;
        }
        if (is != null) {
            try { is.close(); } catch (Exception ignored) {}
            is = null;
        }
        filename = null;
        System.gc();  // 提示 GC 回收 Player 佔用的本地內存
    }

    public void destroy() { close(); }

    // 載入並啟動播放
    private void playFile() {
        if (filename == null) return;
        try {
            is = getClass().getResourceAsStream(filename);
            if (is == null) throw new IOException("Resource not found: " + filename);
            
            player = Manager.createPlayer(is, contentType);
            player.realize();
            
            VolumeControl vc = (VolumeControl) player.getControl("VolumeControl");
            if (vc != null) vc.setLevel(100);  // 最大音量
            
            player.setLoopCount(loopCount);
            player.start();
        } catch (IOException | MediaException e) {
            e.printStackTrace();
        }
    }

    // 控制接口
    public void startPlay() { try { player.start(); } catch (MediaException e) { e.printStackTrace(); } }
    public void pausePlay() { try { player.stop(); } catch (MediaException e) { e.printStackTrace(); } }
    public int getState() { return player != null ? player.getState() : Player.CLOSED; }
}

使用示例

public class GameCanvas extends Canvas {
    private SoundEffects bgm = new SoundEffects(1_000_000); // 背景音樂無限循環
    private SoundEffects sfx = new SoundEffects(1);         // 音效單次播放

    protected void startGame() {
        bgm.playMIDI("/bgm.mid");  // 進入菜單播放背景音樂
    }

    protected void enterGameplay() {
        bgm.close();               // 停止背景音樂
        sfx.playWAV("/jump.wav");  // 播放跳躍音效
    }

    protected void pauseGame() {
        bgm.pausePlay();
    }

    protected void destroy() {
        bgm.destroy();
        sfx.destroy();
    }
}

關鍵經驗總結

問題解決方案
MIDI 不支持多 Player 並發全應用單 Player 實例,播放前 close() 釋放
頻繁切換音效導致卡頓減少音效數量 (建議 1-2 個),避免高頻 createPlayer
長時間運行死機杜絕多線程,單線程複用 + 顯式 close() + System.gc()
無限循環播放setLoopCount(Integer.MAX_VALUE) 或大數值 (100 萬)
音量控制獲取 VolumeControl,setLevel(0-100)

擴展支持格式

通過 contentType 參數統一支持:

  • audio/midi - MIDI (最通用)
  • audio/x-wav - WAV
  • audio/basic - AU
  • audio/mpeg - MP3 (需設備支持 MMAPI)
  • audio/x-tone-seq - Tone Sequence (MIDP 2.0 標準)

總結

在資源受限的 UniJa/功能機平台,單線程複用 Player、顯式資源釋放、控制音效並發數量 是穩定播放音頻的鐵律。本文提供的 SoundEffects 類經實戰驗證,可直接集成到項目中作為音頻管理核心組件。

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