Android四大组件之Service详解(二)——Service在音乐播放器中的使用
前言:上一篇文章我们了解了Service的基本知识,这一节我们将用一个例子来让大家熟悉Service的使用。我们这个例子是关于音乐播放器的例子。
效果图如下:
布局文件activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="music.mp3"
android:textSize="18sp"
android:layout_marginTop="100dp"
android:layout_centerHorizontal="true"/>
<RelativeLayout
android:layout_alignParentBottom="true"
android:layout_marginBottom="160dp"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<SeekBar
android:id="@+id/seekBar"
android:layout_marginTop="80dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<LinearLayout
android:layout_below="@id/seekBar"
android:layout_alignEnd="@id/seekBar"
android:layout_marginRight="20dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
android:id="@+id/music_cur"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="/"/>
<TextView
android:id="@+id/music_length"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
</RelativeLayout>
<LinearLayout
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginBottom="60dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/paly"
android:src="@mipmap/bofang"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<ImageView
android:id="@+id/pause"
android:src="@mipmap/pause"
android:layout_marginLeft="10dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<ImageView
android:id="@+id/stop"
android:src="@mipmap/stop"
android:layout_marginLeft="10dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
</RelativeLayout>
Service服务类,MyService.java
public class MyService extends Service {
MyBinder myBinder = new MyBinder();
MediaPlayer mediaPlayer;
@Override
public void onCreate() {
super.onCreate();
}
@Override
public IBinder onBind(Intent intent) {
return myBinder;
}
public class MyBinder extends Binder{
public MyService getService() {
return MyService.this;
}
}
public void ready(){
mediaPlayer = new MediaPlayer();
try {
// todo: set looping unused
mediaPlayer.setLooping(true);
mediaPlayer.setDataSource("/sdcard/music.mp3");
mediaPlayer.prepare();
} catch (Exception e) {
e.printStackTrace();
}
}
public void play(){
if (!mediaPlayer.isPlaying()) {
mediaPlayer.start();//开始播放
}
}
public void pause() {
if (mediaPlayer != null && mediaPlayer.isPlaying()) {
mediaPlayer.pause();
}
}
public void stop() {
if (mediaPlayer.isPlaying()) {
mediaPlayer.reset();//停止播放
ready();
}
}
public void seekTo(int progress) {
mediaPlayer.seekTo(progress);
}
public int getDuration() {
return mediaPlayer.getDuration();
}
public int getCurrentPosition() {
return mediaPlayer.getCurrentPosition();
}
@Override
public void onDestroy() {
if (mediaPlayer != null && mediaPlayer.isPlaying()) {
mediaPlayer.stop();
mediaPlayer.release();
mediaPlayer = null;
}
super.onDestroy();
}
}
MainActivity.java文件
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private ImageView btnPlay,btnPause,btnStop;
private SeekBar seekBar;
private TextView musicLength,musicCur;
SimpleDateFormat format = new SimpleDateFormat("mm:ss");
private MyService.MyBinder binder;
private boolean isSeekBarChanging;//互斥变量,防止进度条与定时器冲突。
private Timer timer;
// 申请读写权限
private static final int REQUEST_EXTERNAL_STORAGE = 1;
private static String[] PERMISSIONS_STORAGE = {
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE};
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
binder = (MyService.MyBinder) iBinder;
binder.getService().ready();
seekBar.setMax(binder.getService().getDuration());
musicLength.setText(format.format(binder.getService().getDuration())+"");
musicCur.setText("00:00");
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
verifyStoragePermissions(this);
Intent intent = new Intent(this, MyService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
btnPlay.setOnClickListener(this);
btnPause.setOnClickListener(this);
btnStop.setOnClickListener(this);
seekBar.setOnSeekBarChangeListener(new MySeekBar());
}
private void initView() {
btnPlay = (ImageView) findViewById(R.id.paly);
btnPause = (ImageView) findViewById(R.id.pause);
btnStop = (ImageView) findViewById(R.id.stop);
seekBar = (SeekBar) findViewById(R.id.seekBar);
musicCur = (TextView) findViewById(R.id.music_cur);
musicLength = (TextView) findViewById(R.id.music_length);
}
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.paly:
binder.getService().play();
//监听播放时回调函数
timer = new Timer();
timer.schedule(new TimerTask() {
Runnable updateUI = new Runnable() {
@Override
public void run() {
musicCur.setText(format.format(binder.getService().getCurrentPosition())+"");
}
};
@Override
public void run() {
if(!isSeekBarChanging){
seekBar.setProgress(binder.getService().getCurrentPosition());
runOnUiThread(updateUI);
}
}
},0,50);
break;
case R.id.pause:
binder.getService().pause();
break;
case R.id.stop:
binder.getService().stop();
break;
default:
break;
}
}
public static void verifyStoragePermissions(Activity activity) {
int permission = ActivityCompat.checkSelfPermission(activity,
Manifest.permission.WRITE_EXTERNAL_STORAGE);
if (permission != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(
activity,
PERMISSIONS_STORAGE,
REQUEST_EXTERNAL_STORAGE
);
}
}
@Override
protected void onDestroy() {
super.onDestroy();
unbindService(mConnection);
if (timer != null){
timer.cancel();
timer = null;
}
}
/*进度条处理*/
public class MySeekBar implements SeekBar.OnSeekBarChangeListener {
public void onProgressChanged(SeekBar seekBar, int progress,
boolean fromUser) {
}
/*滚动时,应当暂停后台定时器*/
public void onStartTrackingTouch(SeekBar seekBar) {
isSeekBarChanging = true;
}
/*滑动结束后,重新设置值*/
public void onStopTrackingTouch(SeekBar seekBar) {
isSeekBarChanging = false;
binder.getService().seekTo(seekBar.getProgress());
}
}
}
最后在AndroidManifest.xml文件中添加相应的权限申明。
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />