You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 11:22:25