安卓java音乐播放器下一曲_Android音乐播放器的实现-Service 与 MediaPlayer学习后

为了实现后台放歌,可以转移到Service中,具体的逻辑和在Activity中是差不多的

功能需求:

播放,暂停,停止

歌曲进度条(SeekBar)

后台

实现过程

下载4首歌曲改名a1,a2,a3,a4放进sd卡目录下Sounds文件夹

新建服务MediaService

private static final String TAG = "MediaService";

private MyBinder mBinder = new MyBinder();

//标记当前歌曲的序号

private int i = 0;

//歌曲路径

private String[] musicPath = new String[]{

Environment.getExternalStorageDirectory() + "/Sounds/a1.mp3",

Environment.getExternalStorageDirectory() + "/Sounds/a2.mp3",

Environment.getExternalStorageDirectory() + "/Sounds/a3.mp3",

Environment.getExternalStorageDirectory() + "/Sounds/a4.mp3"

};

//这里要是路径有问题,就加上getAbsolutePath(),像下面这样

//Environment.getExternalStorageDirectory().getAbsolutePath() + "/Sounds/a1.mp3",

//初始化MediaPlayer

public MediaPlayer mMediaPlayer = new MediaPlayer();

@Nullable

@Override

public IBinder onBind(Intent intent) {

return mBinder;

}

public class MyBinder extends Binder {

}

在MyBinder类里面添加逻辑功能暂停,播放,下一首,上一首,等

/**

* 播放音乐

*/

public void playMusic() {

if (!mMediaPlayer.isPlaying()) {

//如果还没开始播放,就开始

mMediaPlayer.start();

}

}

/**

* 暂停播放

*/

public void pauseMusic() {

if (mMediaPlayer.isPlaying()) {

//如果还没开始播放,就开始

mMediaPlayer.pause();

}

}

/**

* 下一首

*/

public void nextMusic() {

if (mMediaPlayer != null && i < 4 && i >= 0) {

//切换歌曲reset()很重要很重要很重要,没有会报IllegalStateException

mMediaPlayer.reset();

iniMediaPlayerFile(i + 1);

//这里的if只要是为了不让歌曲的序号越界,因为只有4首歌

if (i == 2) {

} else {

i = i + 1;

}

playMusic();

}

}

/**

* 上一首

*/

public void preciousMusic() {

if (mMediaPlayer != null && i < 4 && i > 0) {

mMediaPlayer.reset();

iniMediaPlayerFile(i - 1);

if (i == 1) {

} else {

i = i - 1;

}

playMusic();

}

}

/**

* 关闭播放器

*/

public void closeMedia() {

if (mMediaPlayer != null) {

mMediaPlayer.stop();

mMediaPlayer.release();

}

}

注意

在下一首和上一首的功能里重新调用 setDataSource时,要先reset再重新加载资源,不然会爆java.lang.IllegalStateException错误,

下面这段有点多余,也是MyBinder里面的,因为可以在Activity中直接获取到MediaPlayer的对象而不用像下面这样拐弯,嗯,暂时先这样写了

/**

* 获取歌曲长度

**/

public int getProgress() {

return mMediaPlayer.getDuration();

}

/**

* 获取播放位置

*/

public int getPlayPosition() {

return mMediaPlayer.getCurrentPosition();

}

/**

* 播放指定位置

*/

public void seekToPositon(int msec) {

mMediaPlayer.seekTo(msec);

}

接着载服务中MediaService中

/**

* 添加file文件到MediaPlayer对象并且准备播放音频

*/

private void iniMediaPlayerFile(int dex) {

//获取文件路径

try {

//此处的两个方法需要捕获IO异常

//设置音频文件到MediaPlayer对象中

mMediaPlayer.setDataSource(musicPath[dex]);

//让MediaPlayer对象准备

mMediaPlayer.prepare();

} catch (IOException e) {

Log.d(TAG, "设置资源,准备阶段出错");

e.printStackTrace();

}

}

加入权限

注册服务

布局文件如下

xmlns:android="http://schemas.android.com/apk/res/android"

xmlns:tools="http://schemas.android.com/tools"

android:id="@+id/activity_main"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:orientation="vertical"

android:paddingBottom="@dimen/activity_vertical_margin"

android:paddingLeft="@dimen/activity_horizontal_margin"

android:paddingRight="@dimen/activity_horizontal_margin"

android:paddingTop="@dimen/activity_vertical_margin"

tools:context="com.minminaya.mediaservice.MainActivity">

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:orientation="horizontal">

android:id="@+id/play"

android:layout_width="0dp"

android:layout_height="50dp"

android:layout_weight="1"

android:text="paly"/>

android:id="@+id/pause"

android:layout_width="0dp"

android:layout_height="50dp"

android:layout_weight="1"

android:text="pause"/>

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:orientation="horizontal">

android:id="@+id/precious"

android:layout_width="0dp"

android:layout_height="50dp"

android:layout_weight="1"

android:text="precious"/>

android:id="@+id/next"

android:layout_width="0dp"

android:layout_height="50dp"

android:layout_weight="1"

android:text="next"/>

android:layout_marginTop="20dp"

android:id="@+id/seekbar"

android:layout_width="match_parent"

android:layout_height="wrap_content"/>

android:text="当前进度:"

android:layout_width="wrap_content"

android:layout_height="wrap_content"/>

android:id="@+id/text1"

android:layout_width="wrap_content"

android:layout_height="wrap_content"/>

预览

Activity中,首先先实现播放的4大功能,声明

private MediaService.MyBinder mMyBinder;

private Button playButton;

private Button pauseButton;

private Button nextButton;

private Button preciousButton;

//“绑定”服务的intent

Intent MediaServiceIntent;

服务与活动的纽带ServiceConnection

private ServiceConnection mServiceConnection = new ServiceConnection() {

@Override

public void onServiceConnected(ComponentName name, IBinder service) {

mMyBinder = (MediaService.MyBinder) service;

Log.d(TAG, "Service与Activity已连接");

}

@Override

public void onServiceDisconnected(ComponentName name) {

}

};

绑定id,这里所有view都绑了,button事件

private void iniView() {

playButton = (Button) findViewById(R.id.play);

pauseButton = (Button) findViewById(R.id.pause);

nextButton = (Button) findViewById(R.id.next);

preciousButton = (Button) findViewById(R.id.precious);

mSeekBar = (SeekBar) findViewById(R.id.seekbar);

mTextView = (TextView) findViewById(R.id.text1);

playButton.setOnClickListener(this);

pauseButton.setOnClickListener(this);

nextButton.setOnClickListener(this);

preciousButton.setOnClickListener(this);

}

button事件详细

@Override

public void onClick(View v) {

switch (v.getId()) {

case R.id.play:

mMyBinder.playMusic();

break;

case R.id.pause:

mMyBinder.pauseMusic();

break;

case R.id.next:

mMyBinder.nextMusic();

break;

case R.id.precious:

mMyBinder.preciousMusic();

break;

}

}

接下来是onCreate方法,针对Android6.0以上的运行时权限,动态申请权限

iniView();

MediaServiceIntent = new Intent(this, MediaService.class);

//判断权限够不够,不够就给

if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {

ActivityCompat.requestPermissions(MainActivity.this, new String[]{

Manifest.permission.WRITE_EXTERNAL_STORAGE

}, 1);

} else {

//够了绑定播放音乐的服务

bindService(MediaServiceIntent, mServiceConnection, BIND_AUTO_CREATE);

}

运行时权限的回调,在Activity中的

//获取到权限回调方法

@Override

public void onRequestPermissionsResult(int requestCode, @NonNull String[]permissions, @NonNull int[] grantResults) {

switch (requestCode) {

case 1:

if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {

bindService(MediaServiceIntent, mServiceConnection, BIND_AUTO_CREATE);

} else {

Toast.makeText(this, "权限不够获取不到音乐,程序将退出", Toast.LENGTH_SHORT).show();

finish();

}

break;

default:

break;

}

}

onDestroy方法种添加

mMyBinder.closeMedia();

unbindService(mServiceConnection);

这个时候可以播放了,进度条当然没有动

效果图

接下来实现进度条的功能

在Activity中实例化handler

private Handler mHandler = new Handler();

private SeekBar mSeekBar;

private TextView mTextView;

//进度条下面的当前进度文字,将毫秒化为m:ss格式

private SimpleDateFormat time = new SimpleDateFormat("m:ss");

在ServiceConnection中添加

mSeekBar.setMax(mMyBinder.getProgress());

mSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {

@Override

public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {

//这里很重要,如果不判断是否来自用户操作进度条,会不断执行下面语句块里面的逻辑,然后就会卡顿卡顿

if(fromUser){

mMyBinder.seekToPositon(seekBar.getProgress());

// mMediaService.mMediaPlayer.seekTo(seekBar.getProgress());

}

}

@Override

public void onStartTrackingTouch(SeekBar seekBar) {

}

@Override

public void onStopTrackingTouch(SeekBar seekBar) {

}

});

mHandler.post(mRunnable);

注意

这里的seekbar回调里,如果不判断fromUser,播放会一直卡顿

还有一个runnable

/**

* 更新ui的runnable

*/

private Runnable mRunnable = new Runnable() {

@Override

public void run() {

mSeekBar.setProgress(mMyBinder.getPlayPosition());

mTextView.setText(time.format(mMyBinder.getPlayPosition()) + "s");

mHandler.postDelayed(mRunnable, 1000);

}

};

onDestroy中 mMyBinder.closeMedia();前添加

//我们的handler发送是定时1000s发送的,如果不关闭,MediaPlayer release掉了还在获取getCurrentPosition就会爆IllegalStateException错误

mHandler.removeCallbacks(mRunnable);

注意关闭handle的队列,不然,转入后台播放时程序崩溃

1.gif

贴全部代码环节

全部Activity代码如下

package com.minminaya.mediaservice;

import android.Manifest;

import android.content.ComponentName;

import android.content.Intent;

import android.content.ServiceConnection;

import android.content.pm.PackageManager;

import android.os.Handler;

import android.os.IBinder;

import android.os.Message;

import android.support.annotation.NonNull;

import android.support.v4.app.ActivityCompat;

import android.support.v4.content.ContextCompat;

import android.support.v7.app.AppCompatActivity;

import android.os.Bundle;

import android.text.format.Time;

import android.util.Log;

import android.view.View;

import android.widget.Button;

import android.widget.SeekBar;

import android.widget.TextView;

import android.widget.Toast;

import com.minminaya.mediaservice.service.MediaService;

import java.text.SimpleDateFormat;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

private Handler mHandler = new Handler();

private static final String TAG = "MainActivity";

private MediaService.MyBinder mMyBinder;

// private MediaService mMediaService;

private Button playButton;

private Button pauseButton;

private Button nextButton;

private Button preciousButton;

private SeekBar mSeekBar;

private TextView mTextView;

//进度条下面的当前进度文字,将毫秒化为m:ss格式

private SimpleDateFormat time = new SimpleDateFormat("m:ss");

//“绑定”服务的intent

Intent MediaServiceIntent;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

iniView();

MediaServiceIntent = new Intent(this, MediaService.class);

//判断权限够不够,不够就给

if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {

ActivityCompat.requestPermissions(MainActivity.this, new String[]{

Manifest.permission.WRITE_EXTERNAL_STORAGE

}, 1);

} else {

//够了就设置路径等,准备播放

bindService(MediaServiceIntent, mServiceConnection, BIND_AUTO_CREATE);

}

}

//获取到权限回调方法

@Override

public void onRequestPermissionsResult(int requestCode, @NonNull String[]permissions, @NonNull int[] grantResults) {

switch (requestCode) {

case 1:

if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {

bindService(MediaServiceIntent, mServiceConnection, BIND_AUTO_CREATE);

} else {

Toast.makeText(this, "权限不够获取不到音乐,程序将退出", Toast.LENGTH_SHORT).show();

finish();

}

break;

default:

break;

}

}

private ServiceConnection mServiceConnection = new ServiceConnection() {

@Override

public void onServiceConnected(ComponentName name, IBinder service) {

mMyBinder = (MediaService.MyBinder) service;

// mMediaService = ((MediaService.MyBinder) service).getInstance();

mSeekBar.setMax(mMyBinder.getProgress());

mSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {

@Override

public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {

//这里很重要,如果不判断是否来自用户操作进度条,会不断执行下面语句块里面的逻辑,然后就会卡顿卡顿

if(fromUser){

mMyBinder.seekToPositon(seekBar.getProgress());

// mMediaService.mMediaPlayer.seekTo(seekBar.getProgress());

}

}

@Override

public void onStartTrackingTouch(SeekBar seekBar) {

}

@Override

public void onStopTrackingTouch(SeekBar seekBar) {

}

});

mHandler.post(mRunnable);

Log.d(TAG, "Service与Activity已连接");

}

@Override

public void onServiceDisconnected(ComponentName name) {

}

};

private void iniView() {

playButton = (Button) findViewById(R.id.play);

pauseButton = (Button) findViewById(R.id.pause);

nextButton = (Button) findViewById(R.id.next);

preciousButton = (Button) findViewById(R.id.precious);

mSeekBar = (SeekBar) findViewById(R.id.seekbar);

mTextView = (TextView) findViewById(R.id.text1);

playButton.setOnClickListener(this);

pauseButton.setOnClickListener(this);

nextButton.setOnClickListener(this);

preciousButton.setOnClickListener(this);

}

@Override

public void onClick(View v) {

switch (v.getId()) {

case R.id.play:

mMyBinder.playMusic();

break;

case R.id.pause:

mMyBinder.pauseMusic();

break;

case R.id.next:

mMyBinder.nextMusic();

break;

case R.id.precious:

mMyBinder.preciousMusic();

break;

}

}

@Override

protected void onDestroy() {

super.onDestroy();

//我们的handler发送是定时1000s发送的,如果不关闭,MediaPlayer release掉了还在获取getCurrentPosition就会爆IllegalStateException错误

mHandler.removeCallbacks(mRunnable);

mMyBinder.closeMedia();

unbindService(mServiceConnection);

}

/**

* 更新ui的runnable

*/

private Runnable mRunnable = new Runnable() {

@Override

public void run() {

mSeekBar.setProgress(mMyBinder.getPlayPosition());

mTextView.setText(time.format(mMyBinder.getPlayPosition()) + "s");

mHandler.postDelayed(mRunnable, 1000);

}

};

}

服务的

package com.minminaya.mediaservice.service;

import android.app.Service;

import android.content.Intent;

import android.media.MediaPlayer;

import android.os.Binder;

import android.os.Environment;

import android.os.IBinder;

import android.support.annotation.Nullable;

import android.util.Log;

import java.io.IOException;

/**

* Created by NIWA on 2017/3/17.

*/

public class MediaService extends Service {

private static final String TAG = "MediaService";

private MyBinder mBinder = new MyBinder();

//标记当前歌曲的序号

private int i = 0;

//歌曲路径

private String[] musicPath = new String[]{

Environment.getExternalStorageDirectory() + "/Sounds/a1.mp3",

Environment.getExternalStorageDirectory() + "/Sounds/a2.mp3",

Environment.getExternalStorageDirectory() + "/Sounds/a3.mp3",

Environment.getExternalStorageDirectory() + "/Sounds/a4.mp3"

};

//初始化MediaPlayer

public MediaPlayer mMediaPlayer = new MediaPlayer();

public MediaService() {

iniMediaPlayerFile(i);

}

@Nullable

@Override

public IBinder onBind(Intent intent) {

return mBinder;

}

public class MyBinder extends Binder {

// /**

// * 获取MediaService.this(方便在ServiceConnection中)

// *

// * *//*

// public MediaService getInstance() {

// return MediaService.this;

// }*/

/**

* 播放音乐

*/

public void playMusic() {

if (!mMediaPlayer.isPlaying()) {

//如果还没开始播放,就开始

mMediaPlayer.start();

}

}

/**

* 暂停播放

*/

public void pauseMusic() {

if (mMediaPlayer.isPlaying()) {

//如果还没开始播放,就开始

mMediaPlayer.pause();

}

}

/**

* reset

*/

public void resetMusic() {

if (!mMediaPlayer.isPlaying()) {

//如果还没开始播放,就开始

mMediaPlayer.reset();

iniMediaPlayerFile(i);

}

}

/**

* 关闭播放器

*/

public void closeMedia() {

if (mMediaPlayer != null) {

mMediaPlayer.stop();

mMediaPlayer.release();

}

}

/**

* 下一首

*/

public void nextMusic() {

if (mMediaPlayer != null && i < 4 && i >= 0) {

//切换歌曲reset()很重要很重要很重要,没有会报IllegalStateException

mMediaPlayer.reset();

iniMediaPlayerFile(i + 1);

//这里的if只要是为了不让歌曲的序号越界,因为只有4首歌

if (i == 2) {

} else {

i = i + 1;

}

playMusic();

}

}

/**

* 上一首

*/

public void preciousMusic() {

if (mMediaPlayer != null && i < 4 && i > 0) {

mMediaPlayer.reset();

iniMediaPlayerFile(i - 1);

if (i == 1) {

} else {

i = i - 1;

}

playMusic();

}

}

/**

* 获取歌曲长度

**/

public int getProgress() {

return mMediaPlayer.getDuration();

}

/**

* 获取播放位置

*/

public int getPlayPosition() {

return mMediaPlayer.getCurrentPosition();

}

/**

* 播放指定位置

*/

public void seekToPositon(int msec) {

mMediaPlayer.seekTo(msec);

}

}

/**

* 添加file文件到MediaPlayer对象并且准备播放音频

*/

private void iniMediaPlayerFile(int dex) {

//获取文件路径

try {

//此处的两个方法需要捕获IO异常

//设置音频文件到MediaPlayer对象中

mMediaPlayer.setDataSource(musicPath[dex]);

//让MediaPlayer对象准备

mMediaPlayer.prepare();

} catch (IOException e) {

Log.d(TAG, "设置资源,准备阶段出错");

e.printStackTrace();

}

}

}

高级播放器。。。人类用的

上面的播放是固有的几个文件(连音频文件名都订好了,真坑)

有个博主,做的毕业项目,是一系列文章,感觉不错,

Android开源音乐播放器之播放器基本功能

注意事项,

几个注意点在上面了

你可能感兴趣的:(安卓java音乐播放器下一曲)