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

将音频从raw目录移至assets目录并保留进度保存功能

从Assets目录播放音频并保留进度保存功能

核心修改点

原代码依赖MediaPlayer.create()直接加载raw目录资源,改为从assets目录加载时,需要通过AssetManager获取音频文件输入流来初始化MediaPlayer,同时完整保留原有的SharedPreferences进度保存与恢复逻辑。

修改后的完整代码

// 补充类成员变量声明
private MediaPlayer mediaPlayer;
private SharedPreferences mPreferences;
private SharedPreferences.Editor editor;
private SeekBar seekBar;
private ImageButton playbttn, lastbuttn;
private boolean playing = true;
private int currentposition;
private Handler handler = new Handler();
private Runnable runnable;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main); // 按实际布局ID调整

    // 初始化控件
    seekBar = findViewById(R.id.seekBar);
    playbttn = findViewById(R.id.playbttn);
    lastbuttn = findViewById(R.id.lastbuttn);

    mPreferences = PreferenceManager.getDefaultSharedPreferences(this);
    editor = mPreferences.edit();

    int mediaprogress = mPreferences.getInt("mediaprogress", 0);
    seekBar.setProgress(mediaprogress); // 直接恢复保存的进度

    seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
        @Override
        public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
            if (fromUser && mediaPlayer != null && mediaPlayer.isPrepared()) {
                seekBar.setProgress(progress);
                mediaPlayer.seekTo(progress);
                editor.putInt("mediaprogress", progress);
                editor.apply();
            }
        }

        @Override
        public void onStartTrackingTouch(SeekBar seekBar) {}

        @Override
        public void onStopTrackingTouch(SeekBar seekBar) {}
    });

    lastbuttn.setOnClickListener(v -> handlePlayPause());
    playbttn.setOnClickListener(v -> handlePlayPause());
}

// 合并重复的播放暂停逻辑
private void handlePlayPause() {
    if (playing) {
        if (mediaPlayer == null) {
            try {
                initMediaPlayer();
                int savedProgress = mPreferences.getInt("mediaprogress", 0);
                mediaPlayer.seekTo(savedProgress);
                mediaPlayer.start();
                editor.putInt("mediaprogress", savedProgress);
                editor.apply();
            } catch (IOException e) {
                e.printStackTrace();
                Toast.makeText(getApplicationContext(), "音频加载失败", Toast.LENGTH_SHORT).show();
            }
        } else if (!mediaPlayer.isPlaying()) {
            mediaPlayer.seekTo(currentposition);
            mediaPlayer.start();
        }
        updateSeekBar();
        playbttn.setImageResource(R.drawable.ic_pause);
        playing = false;
    } else {
        if (mediaPlayer != null && mediaPlayer.isPlaying()) {
            mediaPlayer.pause();
            currentposition = mediaPlayer.getCurrentPosition();
            playbttn.setImageResource(R.drawable.ic_play);
            playing = true;
        }
    }
}

// 初始化Assets目录下的MediaPlayer
private void initMediaPlayer() throws IOException {
    mediaPlayer = new MediaPlayer();
    // 从assets目录获取音频文件描述符
    AssetFileDescriptor afd = getAssets().openFd("audio.mp3");
    mediaPlayer.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
    afd.close();
    mediaPlayer.prepare();
    // 音频播放完成后重置状态
    mediaPlayer.setOnCompletionListener(mp -> {
        playbttn.setImageResource(R.drawable.ic_play);
        playing = true;
        currentposition = 0;
        seekBar.setProgress(0);
        editor.putInt("mediaprogress", 0);
        editor.apply();
    });
}

public void updateSeekBar() {
    if (mediaPlayer != null && mediaPlayer.isPlaying()) {
        int current = mediaPlayer.getCurrentPosition();
        seekBar.setProgress(current);
        int duration = mediaPlayer.getDuration();
        seekBar.setMax(duration);

        editor.putInt("current", current);
        editor.putInt("duration", duration);
        editor.apply();
    }

    runnable = () -> updateSeekBar();
    handler.postDelayed(runnable, 1000);
}

@Override
protected void onStop() {
    super.onStop();
    if (mediaPlayer != null) {
        if (mediaPlayer.isPlaying()) {
            mediaPlayer.pause();
            currentposition = mediaPlayer.getCurrentPosition();
            editor.putInt("mediaprogress", currentposition);
            editor.apply();
        }
        playbttn.setImageResource(R.drawable.ic_play);
    }
    Toast.makeText(getApplicationContext(), "进度已保存", Toast.LENGTH_LONG).show();
}

@Override
protected void onDestroy() {
    super.onDestroy();
    // 释放MediaPlayer资源,避免内存泄漏
    if (mediaPlayer != null) {
        mediaPlayer.release();
        mediaPlayer = null;
    }
    handler.removeCallbacks(runnable);
}

关键改动说明

  1. Assets资源加载:
    放弃MediaPlayer.create(),改用AssetManager.openFd()获取音频文件的文件描述符,通过setDataSource()设置给MediaPlayer,最后调用prepare()完成初始化,适配assets目录的资源读取逻辑。

  2. 进度恢复优化:
    在MediaPlayer初始化并准备完成后,再调用seekTo()跳转到保存的进度,避免因MediaPlayer未就绪导致的状态错误;同时在onStop()中主动保存当前播放位置,确保进度不丢失。

  3. 代码简化与稳定性:
    合并重复的播放暂停逻辑到handlePlayPause()方法,减少冗余;添加MediaPlayer资源释放逻辑(onDestroy()中),避免内存泄漏;增加异常捕获,处理音频加载失败的情况。

内容的提问来源于stack exchange,提问作者Nazzay

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 18:07:16