Android Studio中含自定义Dialog的函数内MediaPlayer与SeekBar问题
解决Dialog中控件获取失败与SeekBar不更新问题
我一眼就看出核心问题了——你用Splash Activity的findViewById()去获取Dialog布局里的SeekBar和playIcon,这肯定拿不到正确的控件实例啊!这些控件属于Dialog专属的activity_auto_play.xml布局,并非Activity的布局,所以你拿到的是null,调用seekBar.setMax()自然会触发空指针崩溃,SeekBar和图标也没法正常更新。
修复步骤&核心要点
- 通过Dialog的根View获取控件:你已经用
LayoutInflater加载了Dialog的布局view,所有Dialog内的控件必须通过这个view来获取,而不是Activity的findViewById。 - 完善SeekBar更新逻辑:需要用Handler定时回调更新进度,同时在MediaPlayer停止或Dialog关闭时终止回调,避免内存泄漏。
- 严格管理MediaPlayer生命周期:在播放完成、取消操作、Dialog关闭时,务必释放MediaPlayer资源,防止内存泄漏和资源占用。
修正后的autoPlayDialog()代码
private void autoPlayDialog() { final MediaPlayer mediaPlayer = MediaPlayer.create(this,R.raw.song2); final SeekBar seekBar; final Runnable updateSeekBarRunnable; final Handler handler = new Handler(); final ImageView playIcon; // 加载Dialog的布局视图 View dialogView = LayoutInflater.from(Splash.this).inflate(R.layout.activity_auto_play,null); // 从Dialog的根视图获取控件(关键修正!) seekBar = dialogView.findViewById(R.id.autoseekbar); playIcon = dialogView.findViewById(R.id.autopauseplay); // 定义SeekBar更新逻辑 updateSeekBarRunnable = new Runnable() { @Override public void run() { if (mediaPlayer.isPlaying()) { seekBar.setProgress(mediaPlayer.getCurrentPosition()); handler.postDelayed(this, 100); // 每100ms更新一次进度 } } }; final AlertDialog dialog = new AlertDialog.Builder(this) .setView(dialogView) .setTitle("new message") .setMessage("Do you want to play?") .setPositiveButton("Yes", null) .setNegativeButton("No", null) .create(); dialog.setOnShowListener(new DialogInterface.OnShowListener() { @Override public void onShow(DialogInterface dialogInterface) { // 确认按钮逻辑 Button positiveBtn = ((AlertDialog) dialog).getButton(AlertDialog.BUTTON_POSITIVE); positiveBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { // 现在能拿到正确的SeekBar实例,不会崩溃了 seekBar.setMax(mediaPlayer.getDuration()); mediaPlayer.start(); playIcon.setImageResource(R.drawable.ic_pause_circle_outline_black_24dp); handler.post(updateSeekBarRunnable); // 启动进度更新 mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { @Override public void onCompletion(MediaPlayer mp) { playIcon.setImageResource(R.drawable.ic_play_circle_outline_black_24dp); handler.removeCallbacks(updateSeekBarRunnable); // 停止进度更新 mediaPlayer.release(); // 释放音频资源 dialog.dismiss(); startActivity(new Intent(Splash.this, MainActivity.class)); } }); } }); // 取消按钮逻辑 Button negativeBtn = ((AlertDialog) dialog).getButton(AlertDialog.BUTTON_NEGATIVE); negativeBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { handler.removeCallbacks(updateSeekBarRunnable); if (mediaPlayer.isPlaying()) mediaPlayer.stop(); mediaPlayer.release(); dialog.dismiss(); startActivity(new Intent(Splash.this, MainActivity.class)); } }); } }); // Dialog关闭时兜底释放资源 dialog.setOnDismissListener(new DialogInterface.OnDismissListener() { @Override public void onDismiss(DialogInterface dialog) { handler.removeCallbacks(updateSeekBarRunnable); if (mediaPlayer.isPlaying()) mediaPlayer.stop(); mediaPlayer.release(); } }); dialog.show(); }
额外提示
- 如果你之前的
changeSeekbar()方法逻辑和上面的updateSeekBarRunnable一致,可以直接替换使用。 - 测试时注意观察音频播放完成、点击取消按钮、强制关闭Dialog这几种场景,确保资源都能正常释放,避免内存泄漏。
内容的提问来源于stack exchange,提问作者Mina Ghadaki
相关产品推荐
相关产品推荐

