音频音乐播放 Service

界面效果:

       

界面就一个播放的Button和一个进度条SeekBar,也可以自己加上两个显示时间的TextView;

点击播放时,有音乐声音,进度条也会自动更新,Button文字变成暂停;

当音乐播放完毕时,Button文字变成播放,进度条重新回原始点;

1、添加权限

这里需要可以读取音频文件的权限:

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

2、添加依赖

本项目中使用EventBus在Service和Activity之间通讯,需要加入EventBus的库:

compile 'org.greenrobot:eventbus:3.0.0'

3、布局文件

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout 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"
    tools:context=".MusicActivity">

    <SeekBar
        android:id="@+id/seekbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.5" />

    <Button
        android:id="@+id/button_play"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="播放"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.6" />

</android.support.constraint.ConstraintLayout>

4、Service

创建Service:new->Service

在Service中,创建一个MediaPlayer对象和一个Binder类,Binder可以用来与Activity之间传输数据(进度条,点击事件),但是只能Activity主动通过Binder进行相互;播放结束后,音乐跳回最开始,并用EventBus主动通知Activity“播放完成”;

代码以及注释如下:

package com.example.m_evolution.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.os.Parcel;
import android.os.RemoteException;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.Log;

import org.greenrobot.eventbus.EventBus;

import java.io.IOException;

public class MusicService extends Service {
    private MediaPlayer mediaPlayer = new MediaPlayer();
    private String file_dir;

    private final int CODE_PLAY_MUSIC = 101;  //播放音乐
    private final int CODE_PAUSE_MUSIC = 102;  //暂停音乐
    private final int CODE_UPDATE_SEEKBAR = 103;  //更新进度条
    private final int CODE_CHANGE_SEEKBAR = 104;  //拖动进度条更新音乐

    public MusicService() {

    }

    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
        file_dir = intent.getExtras().getString("file_dir", Environment.getExternalStorageDirectory()+"/record/"+"a.mp3");
        Log.d("MusicService", file_dir);
        try {
            mediaPlayer.setDataSource(file_dir);
            mediaPlayer.prepare();
            mediaPlayer.setLooping(false);
            mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
                @Override
                public void onCompletion(MediaPlayer mediaPlayer) {
                    try {
                        mediaPlayer.stop();
                        mediaPlayer.prepare();
                        mediaPlayer.seekTo(0);
                        //用EventBus通知Activity已完成播放
                        EventBus.getDefault().post("finish_music");
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            });
        } catch (IOException e) {
            Log.d("MusicService", "未找到文件");
            e.printStackTrace();
        }
        return new MyBinder();
    }

    //Service与Activity交互数据
    public class MyBinder extends Binder{
        @Override
        //code为操作代码
        //data为从Activity中传到Service的数据
        //reply为从Service传到Activity的数据
        protected boolean onTransact(int code, @NonNull Parcel data, @Nullable Parcel reply, int flags) throws RemoteException {
            switch (code)
            {
                case CODE_PLAY_MUSIC:  //播放
                    StartPlay();
                    break;
                case CODE_PAUSE_MUSIC:  //暂停
                    PausePlay();
                    break;
                case CODE_UPDATE_SEEKBAR:  //更新Activity中的进度条
                    int out_data[]=new int[2];  //传出的数据
                    out_data[0] = mediaPlayer.getCurrentPosition();  //获取现在播放时间
                    out_data[1] = mediaPlayer.getDuration();  //获取总时长
                    reply.writeIntArray(out_data);
                    break;
                case CODE_CHANGE_SEEKBAR:
                    int in_data = data.readInt(); //传入的数据:播放时间
                    mediaPlayer.seekTo(in_data);
                    break;
            }
            return super.onTransact(code, data, reply, flags);
        }
    }

    public void StartPlay(){
        if (mediaPlayer!=null && !mediaPlayer.isPlaying()){
            mediaPlayer.start();
        }
    }

    public void PausePlay(){
        if (mediaPlayer!=null && mediaPlayer.isPlaying()){
            mediaPlayer.pause();
        }
    }
}

5、Activity中的代码及注释:

package com.example.m_evolution;

import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Environment;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Parcel;
import android.os.RemoteException;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Button;
import android.widget.SeekBar;

import com.example.m_evolution.Service.MusicService;

import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;

public class MusicActivity extends AppCompatActivity {

    private SeekBar seekBar;
    private Button button_play;
    private String file_dir; //音频文件路径
    private ServiceConnection serviceConnection; //用来连接Service
    private IBinder mBinder;  //用来与Service交互数据
    private boolean isPlaying;  //是否正在进行播放

    private final int CODE_PLAY_MUSIC = 101;  //播放音乐
    private final int CODE_PAUSE_MUSIC = 102;  //暂停音乐
    private final int CODE_UPDATE_SEEKBAR = 103;  //更新进度条
    private final int CODE_CHANGE_SEEKBAR = 104;  //拖动进度条更新音乐

    private final int INIT_VIEW = 0;
    private final int UPDATE_SEEKBAR = 1;

    //更新进度条的线程
    private Thread thread_update_view;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_music);
        //注册EventBus,以便Service通知Activity意播放完毕
        EventBus.getDefault().register(this);

        FindView();
        InitData();
        StartService();  //开启Service
        //初始化进度条以及设置监听器
        new Thread(new Runnable() {
            @Override
            public void run() {
                while(mBinder == null) ;  //等待mBinder被赋值,表示Service成功开始
                Message msg = new Message();
                msg.what = 0;
                mHandler.sendMessage(msg);
            }
        }).start();
    }

    private void FindView(){
        seekBar = findViewById(R.id.seekbar);
        button_play = findViewById(R.id.button_play);
    }

    private void InitData(){
        file_dir = Environment.getExternalStorageDirectory()+"/record/"+"a.mp3";  //这是提前放在手机路径“record”文件夹中的音频文件a.mp3
        isPlaying = false;
    }

    //开启Service
    private void StartService(){
        serviceConnection = new ServiceConnection() {
            //与Service建立连接
            @Override
            public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
                mBinder = iBinder;  //绑定Binder
            }

            @Override
            public void onServiceDisconnected(ComponentName componentName) {
                serviceConnection = null;
            }
        };
        Intent intent = new Intent(this, MusicService.class);
        Bundle bundle = new Bundle();
        bundle.putString("file_dir", file_dir);
        intent.putExtras(bundle);
        startService(intent);
        bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
    }

    private void SetListener(){
        button_play.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if(!isPlaying){ //如果现在是暂停状态
                    StartMusic();
                }
                else{ //如果现在是播放状态
                    PauseMusic();
                }
                isPlaying = !isPlaying;
            }
        });
        //进度条的事件监听器,手指抬起时根据进度条改变音乐播放时间
        seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
            @Override
            public void onProgressChanged(SeekBar seekBar, int i, boolean b) {

            }

            @Override
            public void onStartTrackingTouch(SeekBar seekBar) {

            }

            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {
                int code = CODE_CHANGE_SEEKBAR;
                Parcel data = Parcel.obtain();
                Parcel reply = Parcel.obtain();
                data.writeInt(seekBar.getProgress());  //写入进度条现在的数据
                try {
                    mBinder.transact(code, data, reply, 0);
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
        });
    }

    private void StartMusic(){
        button_play.setText("暂停");
        int code = CODE_PLAY_MUSIC;
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        try {
            mBinder.transact(code,data, reply, 0);  //告诉Service进行播放
        } catch (RemoteException e) {
            e.printStackTrace();
        }
        thread_update_view = new Thread(new Runnable() {
            @Override
            public void run() {
                while (isPlaying && mBinder!=null){
                    Message msg = new Message();
                    msg.what = UPDATE_SEEKBAR;
                    mHandler.sendMessage(msg);
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        });
        thread_update_view.start();
    }

    private void PauseMusic(){
        button_play.setText("播放");
        int code = CODE_PAUSE_MUSIC;
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        try {
            mBinder.transact(code,data, reply, 0);  //告诉Service进行暂停
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }

    //更新Activity中的进度条或TextView等
    private void UpdateView(){
        try {
            int code = CODE_UPDATE_SEEKBAR;
            Parcel data = Parcel.obtain();
            Parcel reply = Parcel.obtain();
            mBinder.transact(code, data, reply, 0);
            int read_data[] = new int[2];  //读取到的音乐播放时间以及总长度
            reply.readIntArray(read_data);
            seekBar.setProgress(read_data[0]);   //音乐正在播放的时间
            seekBar.setMax(read_data[1]);  //音乐总长度
            //这里还可以设置显示时间的TextView
            //......
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }

    private Handler mHandler = new Handler(){
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what) {      //判断标志位
                case INIT_VIEW:   //初始化进度条以及监听器
                    UpdateView();
                    SetListener();
                    break;
                case UPDATE_SEEKBAR:
                    UpdateView();
                    break;
            }
        }
    };

    @Override
    protected void onDestroy() {
        unbindService(serviceConnection);
        serviceConnection = null;
        if(EventBus.getDefault().isRegistered(this)) {
            EventBus.getDefault().unregister(this);
        }
        super.onDestroy();
    }

    //已完成播放
    @Subscribe(threadMode = ThreadMode.MAIN)
    public void Event(String str)
    {
        if(str.equals("finish_music")){
            if(thread_update_view!=null){
                thread_update_view.interrupt();
                thread_update_view = null;
            }
            button_play.setText("播放");
            seekBar.setProgress(0);
            isPlaying = false;
        }
    }
}

6、音频文件

自备一个音频文件,这里我放在了Environment.getExternalStorageDirectory()+"/record/"+"a.mp3"。

猜你喜欢

转载自www.cnblogs.com/zhaozilongcjiajia/p/10723838.html