Android音乐播放器
目录
使用Android多媒体API Media Player来创建一个音乐播放器,要求来电停止播放,电话挂断后继续播放。
搭建整体框架
- 完成app界面的设计
- 定义onClick事件的方法
- 在MainActivity里面获取文本输入框以此来获得本地音乐文件的名字。
- 第2步创建的方法中对点击button进行switch case判断,这里设置了4个button:
a) 播放(btnPlay)
b) 暂停/继续(btnPause)
c) 重播(btnReplay)
d) 停止(btnStop) - 将音乐文件放在SD卡的根目录,并创建File对象,获取文件的绝对路径:
File audioFile=new File(Environment.getExteralStorageDirectory(),filename);
String path=audioFile.getAbsolutePath();
至此完成了整体应用框架的编写。
功能实现
在Button的onClick方法中对v.getId()进行switch case判断,一共有4种情况:
- R.id.btnPlay
- R.id.btnPause
- R.id.btnReplay
- R.id.btnStop
在进一步编写4中情况的具体业务逻辑时,需要一些准备工作。
首先在MainActivity的onCreate方法中已经创建了Android的多媒体对象:
MediaPlayer mediaPlayer=new MediaPlayer()
编写play(position)方法,表示在从特定的位置开始播放。
具体步骤将在代码的注释中体现:
// mediaPlay
try {
mediaPlayer.reset();// 把各项参数恢复到初始状态
mediaPlayer.setDataSource(filePath);//设置数据源
mediaPlayer.prepare();//缓冲数据
mediaPlayer.setOnPreparedListener(new PrepareListener(position));
//完成对缓冲数据的监听
} catch (Exception e) {
e.printStackTrace();
}
}
//内部类用于实现对缓冲事件的监听
private final class PrepareListener implements OnPreparedListener {
private int position;
public PrepareListener(int position) {
this.position=position;
}
@Override
public void onPrepared(MediaPlayer mp) {//数据缓冲完后会执行该方法
mediaPlayer.start();//播放媒体文件
if(position>0){
mediaPlayer.seekTo(position); //从position的位置开始播放
}
}
}
这里需要注意的就是编写内部类实现OnpreparedListener接口完成对数据缓冲的监听,一旦缓冲完成,我们就开始播放媒体文件。
有了play(position)方法,在4个button的条件逻辑就比较简单了,代码如下:
public void mediaPlay(View v) {
String filename = editTextFilename.getText().toString();
switch (v.getId()) {
case R.id.btnPlay:
File audioFile = new File(
Environment.getExternalStorageDirectory(), filename);
if (audioFile.exists()) {
filePath = audioFile.getAbsolutePath();
play(0);
// play
} else {
filePath = null;
Toast.makeText(getApplicationContext(), "文件不存在",
Toast.LENGTH_LONG).show();
}
break;
case R.id.btnPause:
if (mediaPlayer.isPlaying()) {
mediaPlayer.pause();
isPause = true;
((Button) v).setText(R.string.btnContinue);
} else {
if (isPause) {
mediaPlayer.start();
//play(position);
isPause = false;
((Button) v).setText(R.string.btnPause);
}
}
break;
case R.id.btnReplay:
if (mediaPlayer.isPlaying()) {
mediaPlayer.seekTo(0);
} else {
if (filePath != null) {
play(0);
}
}
break;
case R.id.btnStop:
if (mediaPlayer.isPlaying()) {
mediaPlayer.stop();
}
break;
default:
break;
}
}
电话事件监听
首先不要忘了在AndroidMenifest.xml文件中添加权限:
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
在MainActivity中使用TelephonyManager完成对电话事件的监听,这里与上述创建监听准备数据类似,创建继承PhoneStateListener的内部类,通过重写onCallStateChanged方法完成对电话事件的监听:
//来电:
TelephonyManager.CALL_STATE_RINGING
//挂断后:
TelephonyManager.CALL_STATE_IDLE
代码:
private final class MyPhoneListener extends PhoneStateListener {
@Override
public void onCallStateChanged(int state, String incomingNumber) {
switch (state) {
case TelephonyManager.CALL_STATE_RINGING:
if (mediaPlayer.isPlaying()) {
position = mediaPlayer.getCurrentPosition();
mediaPlayer.stop();
}
break;
case TelephonyManager.CALL_STATE_IDLE:
if (position > 0 && filePath != null) {
play(position);
//mediaPlayer.seekTo(position);
position = 0;
}
break;
default:
break;
}
}
}
PS:至此完成了音乐播放器的编写,在这里,我们将音乐播放服务放到了MainActivity.java中。一般情况下我们在MainActivity.java中完成功能框架,在Service组件中完成功能,有时间会将这部分补上。
附录代码
MainActivity.java
public class MainActivity extends Activity {
private EditText editTextFilename;
private String filePath;
private MediaPlayer mediaPlayer;
private boolean isPause;
private int position;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
editTextFilename = (EditText) this.findViewById(R.id.editTextFilename);
mediaPlayer = new MediaPlayer();
TelephonyManager telephonyManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
telephonyManager.listen(new MyPhoneListener(),
PhoneStateListener.LISTEN_CALL_STATE);
}
private final class MyPhoneListener extends PhoneStateListener {
@Override
public void onCallStateChanged(int state, String incomingNumber) {
switch (state) {
case TelephonyManager.CALL_STATE_RINGING:
if (mediaPlayer.isPlaying()) {
position = mediaPlayer.getCurrentPosition();
mediaPlayer.stop();
}
break;
case TelephonyManager.CALL_STATE_IDLE:
if (position > 0 && filePath != null) {
play(position);
//mediaPlayer.seekTo(position);
position = 0;
}
break;
default:
break;
}
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
// 这种方式只要Activity被覆盖就会停止音乐
// @Override
// protected void onPause() {// activity完全被覆盖的时候
// if (mediaPlayer.isPlaying()) {
// position = mediaPlayer.getCurrentPosition();
// mediaPlayer.stop();
// }
// super.onPause();
// }
// @Override
// protected void onResume() {
// if (position > 0 && filePath != null) {
// play();
// mediaPlayer.seekTo(position);
// position = 0;
// }
// super.onResume();
// }
@Override
protected void onDestroy() {
mediaPlayer.release();
mediaPlayer = null;
super.onDestroy();
}
public void mediaPlay(View v) {
String filename = editTextFilename.getText().toString();
switch (v.getId()) {
case R.id.btnPlay:
File audioFile = new File(
Environment.getExternalStorageDirectory(), filename);
if (audioFile.exists()) {
filePath = audioFile.getAbsolutePath();
play(0);
// play
} else {
filePath = null;
Toast.makeText(getApplicationContext(), "文件不存在",
Toast.LENGTH_LONG).show();
}
break;
case R.id.btnPause:
if (mediaPlayer.isPlaying()) {
mediaPlayer.pause();
isPause = true;
((Button) v).setText(R.string.btnContinue);
} else {
if (isPause) {
mediaPlayer.start();
//play(position);
isPause = false;
((Button) v).setText(R.string.btnPause);
}
}
break;
case R.id.btnReplay:
if (mediaPlayer.isPlaying()) {
mediaPlayer.seekTo(0);
} else {
if (filePath != null) {
play(0);
}
}
break;
case R.id.btnStop:
if (mediaPlayer.isPlaying()) {
mediaPlayer.stop();
}
break;
default:
break;
}
}
private void play(int position) {
// mediaPlay
try {
mediaPlayer.reset();// 把各项参数恢复到初始状态
mediaPlayer.setDataSource(filePath);//设置数据源
mediaPlayer.prepare();//缓冲数据
mediaPlayer.setOnPreparedListener(new PrepareListener(position));//完成对缓冲数据的监听
} catch (Exception e) {
e.printStackTrace();
}
}
private final class PrepareListener implements OnPreparedListener {
private int position;
public PrepareListener(int position) {
this.position=position;
}
@Override
public void onPrepared(MediaPlayer mp) {//数据缓冲完后会执行该方法
mediaPlayer.start();//播放媒体文件
if(position>0){
mediaPlayer.seekTo(position); //从position的位置开始播放
}
}
}
}