Java音乐播放器报错Audio data is too big,滑块进度控制异常
Java简易音乐播放器问题修复方案
核心问题分析
1. 滑块无法拖动
Timer调度间隔设为1毫秒,过于频繁更新滑块UI,占用大量UI线程资源导致无法响应拖动操作;同时拖动滑块时未暂停Timer,Timer持续将滑块值强制同步到播放进度,两者冲突导致拖动失效。
2. "Audio data is too big"错误
Clip类设计用于加载小型音频片段,大文件会超出其默认内存限制;- Replayer构造函数中递归创建新的Replayer实例:
frame.setContentPane(new Replayer().Calculator),导致重复加载所有音频文件,内存占用翻倍,触发内存不足错误。
修复步骤
一、替换Timer并调整更新间隔
用Swing Timer替代java.util.Timer,Swing Timer默认在事件调度线程(EDT)执行,避免线程安全问题,同时将更新间隔调整为50毫秒(视觉流畅且不阻塞UI)。
二、解决大音频文件加载问题
通过DataLine.Info指定自定义缓冲区大小,适配大文件加载需求;打开Clip后及时关闭音频输入流,释放资源。
三、修复递归创建实例问题
构造函数中直接使用当前实例的Calculator面板,而非新建Replayer实例。
四、滑块拖动时暂停/恢复进度更新
拖动滑块时暂停Timer,释放后恢复Timer并同步播放进度,避免进度值冲突。
五、确保Swing组件在EDT中初始化
Swing组件必须在事件调度线程中创建,修改Main类用SwingUtilities.invokeLater初始化Replayer。
修改后的完整代码
Main类
import javax.sound.sampled.*; import java.io.IOException; import javax.swing.SwingUtilities; public class Main { public static void main(String[] args) { // 在EDT线程中初始化Swing组件 SwingUtilities.invokeLater(() -> { try { new Replayer(); } catch (UnsupportedAudioFileException | IOException | LineUnavailableException e) { e.printStackTrace(); } }); } }
Replayer类
import javax.sound.sampled.*; import javax.swing.*; import java.awt.event.*; import java.io.File; import java.io.IOException; public class Replayer extends JFrame { long mspos = 0; int selected_track = 0; protected JPanel Calculator; protected JTextField textDisplay; protected JButton PlayButton; protected JButton StopButton; protected JButton PauseButton; protected JButton Next; protected JButton Prev; protected JSlider TrackProgress; private Clip[] clips; private File[] audioFiles; private javax.swing.Timer progressTimer; // 使用Swing Timer public Replayer() throws UnsupportedAudioFileException, IOException, LineUnavailableException { File folder = new File("music"); audioFiles = folder.listFiles((dir, name) -> name.toLowerCase().endsWith(".wav")); if (audioFiles == null || audioFiles.length == 0) { JOptionPane.showMessageDialog(this, "music目录下无WAV文件"); System.exit(1); } clips = new Clip[audioFiles.length]; for (int i = 0; i < audioFiles.length; i++) { AudioInputStream audioStream = AudioSystem.getAudioInputStream(audioFiles[i]); AudioFormat format = audioStream.getFormat(); // 为大文件指定自定义缓冲区 DataLine.Info info = new DataLine.Info(Clip.class, format, AudioSystem.NOT_SPECIFIED); clips[i] = (Clip) AudioSystem.getLine(info); clips[i].open(audioStream); audioStream.close(); // 打开Clip后关闭流,释放资源 } TrackProgress.setValue(0); TrackProgress.setMaximum(1000); // 缩小最大值,提升计算效率 textDisplay.setText(audioFiles[selected_track].getName()); // 初始化Swing Timer,50毫秒更新一次进度 progressTimer = new javax.swing.Timer(50, e -> updateProgress()); progressTimer.start(); PlayButton.addActionListener(e -> { if (clips[selected_track].getMicrosecondPosition() == clips[selected_track].getMicrosecondLength()) { mspos = 0; } clips[selected_track].setMicrosecondPosition(mspos); clips[selected_track].start(); progressTimer.start(); }); StopButton.addActionListener(e -> { mspos = 0; clips[selected_track].stop(); clips[selected_track].setMicrosecondPosition(0); TrackProgress.setValue(0); progressTimer.stop(); }); PauseButton.addActionListener(e -> { clips[selected_track].stop(); mspos = clips[selected_track].getMicrosecondPosition(); progressTimer.stop(); }); Next.addActionListener(e -> { if (selected_track == audioFiles.length - 1) { textDisplay.setText("Error: 已经是最后一首"); } else { clips[selected_track].stop(); progressTimer.stop(); selected_track++; mspos = 0; TrackProgress.setValue(0); textDisplay.setText(audioFiles[selected_track].getName()); } }); Prev.addActionListener(e -> { if (selected_track < 1) { textDisplay.setText("Error: 已经是第一首"); } else { clips[selected_track].stop(); progressTimer.stop(); selected_track--; mspos = 0; TrackProgress.setValue(0); textDisplay.setText(audioFiles[selected_track].getName()); } }); TrackProgress.addMouseListener(new MouseAdapter() { @Override public void mousePressed(MouseEvent e) { clips[selected_track].stop(); progressTimer.stop(); // 拖动时暂停进度更新 } @Override public void mouseReleased(MouseEvent e) { // 根据滑块值计算播放位置 double progress = (double) TrackProgress.getValue() / TrackProgress.getMaximum(); mspos = (long) (progress * clips[selected_track].getMicrosecondLength()); clips[selected_track].setMicrosecondPosition(mspos); clips[selected_track].start(); progressTimer.start(); // 释放后恢复进度更新 } }); // 修复递归创建问题,使用当前实例的面板 setContentPane(this.Calculator); setTitle("Replayer"); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setResizable(false); pack(); setVisible(true); } // 更新滑块进度的方法 private void updateProgress() { Clip currentClip = clips[selected_track]; if (currentClip.isRunning()) { long currentPos = currentClip.getMicrosecondPosition(); long totalLength = currentClip.getMicrosecondLength(); int progress = (int) ((double) currentPos / totalLength * TrackProgress.getMaximum()); TrackProgress.setValue(progress); } } }
额外优化建议
- 添加窗口关闭事件监听,关闭所有Clip释放音频资源;
- 优化滑块交互,添加
ChangeListener支持拖动过程中实时预览进度; - 增加音频文件格式校验,避免加载非标准WAV文件。
内容的提问来源于stack exchange,提问作者Jacob Hey
相关产品推荐
相关产品推荐

