概述
上次已经为 Miwok 应用的每个页面的列表项设置了单词图片和 主题色
接下来将 为 所有页面的 单词 和 词组 添加音频播放的功能,使在屏幕中单击 任意一个 单词或词组使,播放对应的音频文件。
不过在此之前,有必要 先创建一个与 Miwok 应用独立开来的 小型音频播放应用。
开发者通常会写一个小应用来测试下新技术,然后将该技术添加到自己的大型应用中。
目标
- 新创建一个小型音频播放应用
- 应用中有一个播放按钮用于播放音频
- 应用中有一个暂停按钮用于暂停播放
- 两个用于快进和后退的按钮
实现过程
应用布局
这个音频播放器的外观和 日常生活中所使用的音乐播放器 类似:
可以看出 音乐播放应用的界面基本分为上下两部分:
上部分显示音乐播放器的 名称和图片,下部分为 音频的控制区域 ,用于控制音频的 播放、暂停、快进、后退,还有一个拖动条 用于实时显示 音频播放的文章。
下部分中还有三个文本其余,用于显示 音频的名称、总时长 和 播放的位置。
媒体播放器
在此之前我并不会在 Android 应用 中 播放 音频,经过在网上查阅之后 发现可以使用 MediaPlayer API 来实现音频的播放等操作,接着再查看 Android MediaPlayer 的相关文档,了解基本的使用方法(相关文章的链接为都放到了文末的参考链接当中)。
在 Android app 中 ,主要使用一下代码实现 音频的播放:
class MainActivity extends Activity {
MediaPlayer mediaPlayer;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mediaPlayer = MediaPlayer.create(getApplicationContext(), R.raw.yoursong);
mediaPlayer.start();
}
@Override
protected void onPause() {
super.onPause();
mediaPlayer.stop();
mediaPlayer.release();
}
}
- 2 行,在 Activity 中 声明 一个 MediaPlayer 类型的 媒体播放器 成员变量
- 9 行,创建 MediaPlayer 对象 ,传入 上下文 context 和 音频资源文件的id
- 10 行,启动 媒体播放器,即 开始播放音频
- 13 ~ 18 行,当Activity 被暂停后,关掉 媒体播放器,并释放其占用的内存资源
在 第 9 行 为 媒体播放器 指定音频资源id,使用的是 raw
类型的资源(需要新建),在右侧的 res
目录上鼠标右键 --> 选择 New --> 选择 Android Resource Directory。
接着 在弹出的窗口中 将 Resource type
选成 raw
,这时 Directory name
页面 变成 raw
,最后点击 ok
即可完成 raw 类型资源目录的创建。
然后将音频文件放到 raw 文件夹当中,就可以在代码中以 R.raw.song
的形式来访问 资源ID了。
由于版权原因,不提供任何音频文件。建议自己选择一个 可用且有趣的音频文件,并添加到自己的 Music Player 应用中。
进度条和时间显示
首先获取所有需要用到的控件的视图对象,并设置其初始状态
在 onCreate
方法中添加:
playButton = (Button) findViewById(R.id.play_button);
pauseButton = (Button) findViewById(R.id.pause_button);
forwardButton = (Button) findViewById(R.id.forward_button);
backwardButton = (Button) findViewById(R.id.backward_button);
playedTime = (TextView) findViewById(R.id.played_time_text_view);
totalTime = (TextView) findViewById(R.id.total_time_text_view);
musicName = (TextView) findViewById(R.id.music_name_text_view);
musicName.setText("Always With Me - Meja");
mediaPlayer = MediaPlayer.create(this, R.raw.always_with_me_by_meja);
seekbar = (SeekBar) findViewById(R.id.seekBar);
seekbar.setClickable(false);
pauseButton.setEnabled(false);
- 9 行,设置默认显示的音频名称
- 13 行,禁止拖动 音频的进度条(拖动条)
- 14 行,禁用暂停按钮
不要往先在 MainActivity
中声明这些成员变量:
private Button forwardButton, pauseButton, playButton, backwardButton;
private MediaPlayer mediaPlayer;
private double startTime = 0;
private double finalTime = 0;
private Handler myHandler = new Handler();
private final int forwardTime = 5000;
private final int backwardTime = 5000;
private SeekBar seekbar;
private TextView playedTime, totalTime, musicName;
public static int oneTimeOnly = 0;
播放功能
点击播放按钮时即播放音频,触发 OnClick 事件,因此为 播放按钮注册 OnClickListener 如下:
playButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(getApplicationContext(), "Playing sound", Toast.LENGTH_SHORT).show();
mediaPlayer.start();
finalTime = mediaPlayer.getDuration();
startTime = mediaPlayer.getCurrentPosition();
if (oneTimeOnly == 0) {
seekbar.setMax((int) finalTime);
oneTimeOnly = 1;
}
totalTime.setText(String.format("%02d:%02d",
TimeUnit.MILLISECONDS.toMinutes((long) finalTime),
TimeUnit.MILLISECONDS.toSeconds((long) finalTime) -
TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes((long)
finalTime)))
);
playedTime.setText(String.format("%02d:%02d",
TimeUnit.MILLISECONDS.toMinutes((long) startTime),
TimeUnit.MILLISECONDS.toSeconds((long) startTime) -
TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes((long)
startTime)))
);
seekbar.setProgress((int) startTime);
myHandler.postDelayed(UpdateSongTime, 100);
pauseButton.setEnabled(true);
playButton.setEnabled(false);
}
});
- 4 行,消息框提示
- 6 行,启动媒体播放器,开始播放音频
- 8 - 9 行,获取被播放音频的开始时间和 总时长
- 11 - 14 行,判断是否为首次播放音频,并设置拖动条的最大值
- 16 -21 行,在页面中显示 音频的总时长
- 23 - 28行,在页面中显示 已经已经播放的音频时长
- 30 行,设置 拖动条的焦点 到音频开始播放的位置
- 32 行,启动暂停按钮
- 33 行,禁用播放按钮
暂停功能
点击暂停按钮时即停止播放,触发 OnClick 事件,因此为 播放按钮注册 OnClickListener 如下:
pauseButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(getApplicationContext(), "Pausing sound", Toast.LENGTH_SHORT).show();
mediaPlayer.pause();
pauseButton.setEnabled(false);
playButton.setEnabled(true);
}
});
- 5 行,暂停媒体播放器
- 6 行,禁用暂停按钮
- 7 行,启用播放按钮
当点击暂停按钮后,自然不能再按暂停,而是等待 点击 播放按钮 播放音频。
快进功能
每点击快进按钮一次,将音频的播放位置快进 5 秒。
forwardButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int temp = (int) startTime;
if ((temp + forwardTime) <= finalTime) {
startTime = startTime + forwardTime;
mediaPlayer.seekTo((int) startTime);
// Toast.makeText(getApplicationContext(), "You have Jumped forward 5 seconds", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(getApplicationContext(), "Cannot jump forward 5 seconds", Toast.LENGTH_SHORT).show();
}
}
});
在 6- 12 行中,首先 判断 音频当前播放到的位置是否可以 快进 5秒 ,如可以,则使媒体播放器的播放位置 跳转 的当前时间 再加 5 秒的位置;反之则弹出提示,,表示不能快进。
后退功能
每点击后退按钮一次,将音频的播放位置后退 5 秒。
backwardButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int temp = (int) startTime;
if ((temp - backwardTime) > 0) {
startTime = startTime - backwardTime;
mediaPlayer.seekTo((int) startTime);
// Toast.makeText(getApplicationContext(), "You have Jumped backward 5 seconds", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(getApplicationContext(), "Cannot jump backward 5 seconds", Toast.LENGTH_SHORT).show();
}
}
});
}
在 5- 11 行中,首先 判断 音频当前播放到的位置是否可以 后退 5秒 ,如可以,则使媒体播放器的播放位置 跳转 的当前时间 再减去 5 秒的位置;反之则弹出提示,,表示不能后退。
总结
音频的播放和暂停功能相对来说还是容易实现的,而 快进 和 后退 功能则稍难一点 ,主要是 获取音频实时播放到的位置。
最后遇到一个问题,我为媒体播放器 对象 绑定了一个 当音频播放完成十触发的监听器 OnCompletionListener
,本打算当音频播放完成时回收音频暂用的内存资源,但当我使用 Toast
测试该功能时失败了,目前仍待解决。
参考
MediaPlayer | Android Developers