将音频从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); }
关键改动说明
Assets资源加载:
放弃MediaPlayer.create(),改用AssetManager.openFd()获取音频文件的文件描述符,通过setDataSource()设置给MediaPlayer,最后调用prepare()完成初始化,适配assets目录的资源读取逻辑。进度恢复优化:
在MediaPlayer初始化并准备完成后,再调用seekTo()跳转到保存的进度,避免因MediaPlayer未就绪导致的状态错误;同时在onStop()中主动保存当前播放位置,确保进度不丢失。代码简化与稳定性:
合并重复的播放暂停逻辑到handlePlayPause()方法,减少冗余;添加MediaPlayer资源释放逻辑(onDestroy()中),避免内存泄漏;增加异常捕获,处理音频加载失败的情况。
内容的提问来源于stack exchange,提问作者Nazzay
相关产品推荐
相关产品推荐

