一、前言
最近在做盲人导航,需要根据周围的环境不断在后台播放提示语音。查了下资料,找到一个效果还可以的源码。
二、思路概括
1.把要播放的曲目通过mp3的格式放在src的raw文件夹里,这样可以通过R.raw.xxx获得相应的ID。
2.新建一个全局变量MusicName,用于存放需要播放的声音的名字。
3.新建一个在后台运行的线程,随时播放声音,播放的曲目根据全局变量MusicName的改变而改变。
这样一来,在程序的某个位置改变MusicName时,就可以改变背景音乐,实现实时提示的效果,且不影响主线程的运行。
三、实现方法
1.建立全局变量
用public class的方法新建一个全局变量,我这里命名为MusicName,方便其他activity随时指定。注意这个全局变量的数据类型是int,因为通过R.raw.xxx方式制定的MP3路径是int格式的。
注意把第一行package的路径改为自己的。
//路径改为自己的
package com.example.myapplication;
public class MusicName {
private static int name = 0;
public static int getName() {
return name;
}
public static void setName(int name) {
MusicName.name = name;
}
}
2.建立一个AudioService 的类
新建一个名为AudioService 的类。代码如下。
//package 改为自己的路径
package com.example.myapplication;
import android.app.Service;
/**
* 多线程实现后台播放背景音乐的service
*/
import android.app.Service;
import android.content.Intent;
import android.media.MediaPlayer;
import android.os.Binder;
import android.os.IBinder;
public class AudioService extends Service implements
MediaPlayer.OnCompletionListener {
// 实例化MediaPlayer对象
MediaPlayer player;
private final IBinder binder = new AudioBinder();
@Override
public IBinder onBind(Intent intent) {
return binder;
}
public void onCreate() {
super.onCreate();
// 从raw文件夹中获取一个应用自带的mp3文件
player = MediaPlayer.create(this, R.raw.silent);
player.setOnCompletionListener(this);
player.setLooping(true);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
if (!player.isPlaying()) {
new MusicPlayThread().start();
} else
player.isPlaying();
return START_STICKY;
}
/**
* 当Audio播放完的时候触发该动作
*/
public void onCompletion(MediaPlayer mp) {
stopSelf();// 结束了,则结束Service
}
public void onDestroy() {
super.onDestroy();
if (player.isPlaying()) {
player.stop();
}
player.release();
}
// 为了和Activity交互,我们需要定义一个Binder对象
public class AudioBinder extends Binder {
// 返回Service对象
public AudioService getService() {
return AudioService.this;
}
}
private class MusicPlayThread extends Thread {
public void run() {
if (!player.isPlaying()) {
player.start();
}
}
}
}
注意:
(1)直接复制的话,要把第一行package的路径改为自己的。
(2)代码要求SDK最低版本是21。
(3)由于代码设计逻辑不够完善,最开始要制定一段空白音乐给系统播放。
player = MediaPlayer.create(this, R.raw.silent);
这段空白音频我放在这里了,大家可以下载一下。
链接:https://pan.baidu.com/s/1kaIAJpxJff-V0XvpS62u3g
提取码:24gi
3.在你的activity中建立一个线程,放入播放音乐的函数
在某个Activity的onCreate函数建立线程,以及在public class的层级加入playBGsound()函数。总共两部分,在你的代码中加入注释中的部分即可。直接复制的话,注意我的activity命名是"MainActivity_rs",要改成自己的。
public class MainActivity_rs extends AppCompatActivity {
//************加入部分1**********
MediaPlayer mp=null;//声明一个MediaPlayer对象
private void playBGSound(){
if(mp!=null){
mp.release();//释放资源
}
while (MusicName.getName()==0);
//播放的曲目取决于MusicName的值
mp=MediaPlayer.create(MainActivity_rs.this, MusicName.getName());
mp.start();
//为MediaPlayer添加播放完成事件监听
mp.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mp) {
try {
Thread.sleep(10);//暂停时间(毫秒)
playBGSound();//重新播放音乐
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
}
//************加入部分1**********
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//这个layout是我自己的,不要直接复制
setContentView(R.layout.activity_main_rs);
//************加入部分2**********
Thread music_thread;//声明一个线程对象
music_thread = new Thread(new Runnable() {
@Override
public void run() {
playBGSound();//播放背景音乐
}
});
music_thread.start();//开启线程
//************加入部分2**********
}
}
4.动态改变播放的音乐
大功告成!系统此时应该就会开始不间断地播放声音了。由于默认播放的是空白音乐(意味着没声音),因此需要在程序运行中人为指定。例如,要想改变播放的音频,可以这样操作:
MusicName.setName(R.raw.left60_fast);
由于播放后台音乐的线程会不断读取全局变量MusicName的值,因此当MusicName改变时,播放音乐也会随之改变。注意这里的R.raw.left60_fast是我个人的音频,大家可以替换为其他的MP3。
5.停止播放的方法
解决方法:stopService()和stopSelf()都可以停止通过startService()方式启动的service。stopService需要传递startService(Intent
service)时的intent对象作为参数,停止此intent对应的service。stopSelf直接停止本service,不需要参数,在service中直接调用即可。
6.附:目录结构
标红的地方是需要改动的。注意我是在MainActivity_rs中改动的,大家也可以换成其他的activity。