实现效果图:
使用service在后台播放音乐,拖动进度条,与服务进行交互,改变音乐的播放进度
(1)首先,我们需要申请读取本地文件的权限,播放本机的音乐
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
(2)把服务注册了。因为服务是四大组件之一,需要注册,位置和activity平行
<service
android:name="com.example.administrator.testz.MusicService"
android:enabled="true"
android:exported="true">
</service>
(3)使用MyBind接收数据,进出处理 ,重点是code,根据code的值来进行服务和界面的交互
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.app.Service;
import android.content.Intent;
import android.media.MediaPlayer;
import android.os.Binder;
import android.os.Build;
import android.os.IBinder;
import android.os.Parcel;
import android.os.RemoteException;
import android.support.annotation.Nullable;
import android.support.annotation.RequiresApi;
import android.view.animation.LinearInterpolator;
import java.io.IOException;
/**
* Created by Administrator on 2018\11\13 0013.
*/
public class MusicService extends Service {
private int flag = 0;
public static MediaPlayer mediaPlayer = new MediaPlayer();
private IBinder mBinder = new MyBinder();
public static ObjectAnimator animator;
public static String which= "";
public static int returnFlag = 0;
@Nullable
@Override
public IBinder onBind(Intent intent) {
return mBinder;//一定要返回binder
}
public class MyBinder extends Binder{
@Override
protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
switch (code){
case 101:
//播放 处理服务的函数
playOrPauseHandler();
break;
case 102:
//处理服务的函数 停止
stopHandler();
break;
case 103:
//处理服务的函数 退出
quitHandler();
break;
case 104:
//处理服务的函数 界面刷新
break;
case 105:
//处理服务的函数 拖动进度处理
break;
default:
break;
}
return super.onTransact(code, data, reply, flags);
}
}
//退出
private void quitHandler() {
animator.end();
mediaPlayer.stop();
mediaPlayer.release();
}
//停止
private void stopHandler() {
which = "stop";
animator.pause();
if(mediaPlayer != null){
mediaPlayer.pause();
mediaPlayer.stop();
try {
mediaPlayer.prepare();
mediaPlayer.seekTo(0);
} catch (IOException e) {
e.printStackTrace();
}
}
}
//播放
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
private void playOrPauseHandler() {
flag++;
if(flag>=1000){
flag=2;
}
which = "pause";
if(mediaPlayer.isPlaying()){
mediaPlayer.pause();
animator.pause();
}else {
mediaPlayer.start();
if(flag==1 || returnFlag == 1){
animator.setDuration(5000); //设置持续时间
animator.setInterpolator(new LinearInterpolator()); //设置匀速转动
animator.setRepeatCount(ValueAnimator.INFINITE); //设置无限循环
animator.setRepeatMode(ValueAnimator.RESTART); //设置重复模式 RESTART:重新从头开始执行。 REVERSE:反方向执行
animator.start(); //开始
}else{
animator.start();
}
}
}
//获取文件路径 设置播放属性
public MusicService(){
try {
String Assets_path1 = "/storage/emulated/0/Android/data/暗香.mp3";
mediaPlayer.setDataSource(Assets_path1);
mediaPlayer.prepare(); //prepare()或prepareAsync()方法把流媒体装载进MediaPlayer,调用start()方法播放流媒体
mediaPlayer.setLooping(true); //设置是否循环播放。
}catch (Exception e){
e.printStackTrace();
}
}
//设置转动
public void setAnimation(){
if(mediaPlayer.isPlaying()){
animator.setDuration(5000); //设置持续时间
animator.setInterpolator(new LinearInterpolator()); //设置匀速转动
animator.setRepeatCount(ValueAnimator.INFINITE); //设置无限循环
animator.setRepeatMode(ValueAnimator.RESTART); //设置重复模式 RESTART:重新从头开始执行。 REVERSE:反方向执行
animator.start(); //开始
}
}
@Override
public void onDestroy() {
super.onDestroy();
mediaPlayer.stop();
mediaPlayer.release(); //释放资源
}
}
(4)主界面调用
import android.Manifest;
import android.animation.ObjectAnimator;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.pm.PackageManager;
import android.icu.text.SimpleDateFormat;
import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
import android.os.Parcel;
import android.os.RemoteException;
import android.support.annotation.NonNull;
import android.support.annotation.RequiresApi;
import android.support.v4.app.ActivityCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.SeekBar;
import android.widget.TextView;
import android.widget.Toast;
@RequiresApi(api = Build.VERSION_CODES.N)
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private IBinder mBinder;
private ServiceConnection mConnection;
/*控件*/
private Button playButton;
private Button stopButton;
private Button quitButton;
private ImageView image;
private TextView currentTime;
private TextView endTime;
private TextView txt_state;
private SeekBar seekBar;
private MusicService musicService;
private SimpleDateFormat time = new SimpleDateFormat("mm:ss");
public Handler handler = new Handler();
public Runnable runnable = new Runnable() {
@Override
public void run() {
if(musicService.mediaPlayer.isPlaying()){
txt_state.setText("Playing");
}else{
if(musicService.which.equals("stop")){
txt_state.setText("stop");
}else if(musicService.which.equals("pause")){
txt_state.setText("pause");
}
}
currentTime.setText(time.format(musicService.mediaPlayer.getCurrentPosition()));
endTime.setText(time.format(musicService.mediaPlayer.getDuration()));
seekBar.setProgress(musicService.mediaPlayer.getCurrentPosition());
seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
if(b){
//直接拖懂 mediaplayer的seekto方法
musicService.mediaPlayer.seekTo(seekBar.getProgress());
}
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
handler.postDelayed(runnable,100);
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
musicService = new MusicService();
//绑定服务,开启服务
mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
mBinder = iBinder; //数据绑定
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
mConnection = null;
}
};
Intent intent = new Intent(this,MusicService.class);
startService(intent);
bindService(intent,mConnection, Context.BIND_AUTO_CREATE);
//初始化
initViews();
initEvent(); //事件
}
private void initEvent() {
playButton.setOnClickListener(this);
stopButton.setOnClickListener(this);
quitButton.setOnClickListener(this);
}
private void initViews() {
image = (ImageView)findViewById(R.id.image);
txt_state = (TextView)findViewById(R.id.txt_state);
currentTime = (TextView)findViewById(R.id.start_time);
endTime = (TextView)findViewById(R.id.end_time);
seekBar = (SeekBar)findViewById(R.id.seekbar);
playButton = (Button)findViewById(R.id.isPlayButton);
stopButton = (Button)findViewById(R.id.stopButton);
quitButton = (Button) findViewById(R.id.quitButton);
musicService.animator = ObjectAnimator.ofFloat(image,"rotation",0,350); //动画绑定
}
@Override
public void onClick(View view) {
switch (view.getId()){
case R.id.isPlayButton:
playButtonHandler();
break;
case R.id.stopButton:
stopButtonHandler();
break;
case R.id.quitButton:
quitButtonHanler();
break;
}
}
//退出
private void quitButtonHanler() {
try {
int code = 103;
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
mBinder.transact(code,data,reply,0);
}catch (RemoteException e){
e.printStackTrace();
}
handler.removeCallbacks(runnable);
unbindService(mConnection);
try {
finish();
System.exit(0);
}catch (Exception e){
e.printStackTrace();
}
}
private void stopButtonHandler() {
try {
int code = 102;
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
mBinder.transact(code,data,reply,0);
}catch (RemoteException e){
e.printStackTrace();
}
}
private void playButtonHandler() {
if(musicService.mediaPlayer.isPlaying()){
txt_state.setText("Pause");
playButton.setText("play");
}else{
txt_state.setText("Playing");
playButton.setText("Pause");
}
try {
int code = 101;
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
mBinder.transact(code,data,reply,0);
}catch (RemoteException e){
e.printStackTrace();
}
}
@Override
protected void onResume() {
super.onResume();
if(musicService != null){
musicService.setAnimation();
}
checkStoragePerssion(this);
if(musicService.mediaPlayer.isPlaying()){
txt_state.setText("playing");
}else{
if(musicService.which.equals("stop")){
txt_state.setText("stop");
}else if(musicService.which.equals("pause")){
txt_state.setText("pause");
}
}
seekBar.setProgress(musicService.mediaPlayer.getCurrentPosition()); //获取当前进度
seekBar.setMax(musicService.mediaPlayer.getDuration()); //获取最大值
handler.post(runnable);
}
private void checkStoragePerssion(MainActivity mainActivity) {
String[] PERMISSIONS_STORAGE = {Manifest.permission.READ_EXTERNAL_STORAGE,Manifest.permission.WRITE_EXTERNAL_STORAGE};
final int REQUEST_EXTERNAL_STORAGE = 1;
try{
int permission = ActivityCompat.checkSelfPermission(mainActivity,"android.permission.READ_EXTERNAL_STORAGE");
if(permission!= PackageManager.PERMISSION_GRANTED){
ActivityCompat.requestPermissions(mainActivity,PERMISSIONS_STORAGE,REQUEST_EXTERNAL_STORAGE);
}
}catch (Exception e){
e.printStackTrace();
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
if(grantResults.length>0&&grantResults[0]== PackageManager.PERMISSION_GRANTED){
Toast.makeText(MainActivity.this,"您已授予应用权限",Toast.LENGTH_SHORT).show();
}else{
Toast.makeText(MainActivity.this,"应用权限不足,启动失败",Toast.LENGTH_SHORT).show();
System.exit(0);
}
return;
}
@Override
protected void onRestart() {
super.onRestart();
musicService.returnFlag = 1;
}
@Override
protected void onDestroy() {
super.onDestroy();
unbindService(mConnection);
mConnection = null;
try {
MainActivity.this.finish();
}catch (Exception e){
e.printStackTrace();
}
}
}
(5)界面效果
<ImageView
android:layout_width="200dp"
android:layout_height="200dp"
android:id="@+id/image"
android:layout_marginTop="20dp"
android:scaleType="centerInside"
android:layout_centerHorizontal="true"
android:src="@mipmap/likena" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/txt_state"
android:text=""
android:layout_below="@+id/image"
android:padding="15dp"/>
<TableRow
android:id="@+id/tbr_row1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/txt_state"
android:padding="15dp">
<TextView
android:id="@+id/start_time"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_weight="1"
android:text="00:00"
android:textSize="20sp" />
<SeekBar
android:layout_width="0dp"
android:layout_weight="4"
android:layout_height="wrap_content"
android:id="@+id/seekbar"
android:layout_gravity="center_vertical" />
<TextView
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:id="@+id/end_time"
android:text="00:00"
android:textSize="20sp"/>
</TableRow>
<TableRow
android:id="@+id/tbr_row2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/tbr_row1"
android:gravity="center_horizontal"
android:padding="15dp">
<Button
android:id="@+id/isPlayButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="22dp"
android:text="PLAY" />
<Button
android:id="@+id/stopButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="22dp"
android:text="STOP"
android:layout_marginLeft="15dp"
android:layout_marginRight="15dp"/>
<Button
android:id="@+id/quitButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="22dp"
android:text="QUIT" />
</TableRow>