一个简易的音频播放器实现

   日期:2020-11-12     浏览:98    评论:0    
核心提示:一个简易的音频播放器实现XML代码块<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:orientation="vertical" android:layout_height="match_parent"

一个简易的音频播放器实现

XML代码块

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:orientation="vertical" android:layout_height="match_parent">

    <SeekBar android:id="@+id/seek_bar" android:max="100" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="10dp"/>
    <LinearLayout android:layout_marginTop="5dp" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center">
        <Button android:id="@+id/play_or_pause" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="播放"/>
         <Button android:id="@+id/stop" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="停止"/>

    </LinearLayout>

</LinearLayout>

界面图片

实现功能

  • 可以通过拖动进度条来播放音乐,音乐播放时进度条也会跟着移动,当播放完毕时进度条走满
  • 点击播放键进入播放状态,同时按键文字变为“暂停”,点击“暂停”时暂停播放,文字变为“播放”,下次再点击“播放”将继续从上次播放位置播放
  • 在任意状态点击“停止”将会停止播放,下次播放从头开始

定义好功能接口,能控制播放功能以及UI界面改变功能。

public interface IPlayControl { 
    //播放状态
    int PLAYER_STATE_PLAY=1;
    int PLAYER_STATE_PAUSE=2;
    int PLAYER_STATE_STOP=3;
    
    void registerViewController(IPlayViewControl iPlayViewControl);

    
    void unregisterViewController();
    
    void playOrPause();
    
    void stop();
    
    void seekTo(float seek);
}

public interface IPlayViewControl { 
    
    void onPlayerStateChange(int state);
    
    void onSeekChange(float seek);
}

在Activity中

@RequiresApi(api = Build.VERSION_CODES.M)
public class MainActivity extends AppCompatActivity { 

    private static final String TAG = "MainActivity";
    private static final int PERMISSION_CODE = 1;
    private SeekBar mSeekBar;
    private Button mPlayOrPause;
    private Button mStop;
    private boolean mIsBind;
    private IPlayControl mIPlayControl;
    private boolean isUserTouchProgress;


    @Override
    protected void onCreate(Bundle savedInstanceState) { 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //初始化控件
        initView();
        //设置事件监听
        initListener();
        //开启服务(因为绑定服务不能长期运行,所以采用二者结合的方式)
        startService(new Intent(this, PlayService.class));
		//因为要要在内存卡中读取音乐,需要获得运行时权限(模拟器api27,大于等于29的需要在
        //AndroidManifest.xml中添加android:requestLegacyExternalStorage="true")
        if ((checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE)!= PackageManager.PERMISSION_GRANTED)) { 
            requestPermissions(new String[]{ Manifest.permission.READ_EXTERNAL_STORAGE},PERMISSION_CODE);
        }else { 
            //绑定服务
            initBindService();
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { 
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if(requestCode==PERMISSION_CODE){ 
            if(grantResults[0]==PackageManager.PERMISSION_GRANTED){ 
                //绑定服务
                initBindService();
            }
        }
    }

    
    private void initBindService() { 
        Intent intent = new Intent(MainActivity.this, PlayService.class);
        mIsBind = bindService(intent, mConnection, BIND_AUTO_CREATE);
        Log.d(TAG, "bindService..");
    }

    private ServiceConnection mConnection = new ServiceConnection() { 
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) { 
            mIPlayControl = (IPlayControl) service;
            mIPlayControl.registerViewController(mIPlayViewControl);
            Log.d(TAG,"mConnection..");
        }

        @Override
        public void onServiceDisconnected(ComponentName name) { 
            //如果断开连接就把它置空
            mIPlayControl = null;
        }
    };

    private void initListener() { 
        mSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { 
            @Override
            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { 
                //进度条发生改变

            }

            @Override
            public void onStartTrackingTouch(SeekBar seekBar) { 
                //用户用手拖动进度条
                isUserTouchProgress=true;

            }

            @Override
            public void onStopTrackingTouch(SeekBar seekBar) { 
                //进度条停止拖动,获得当前进度
                int touchProgress = seekBar.getProgress();
                Log.d(TAG, "touchProgress==" + touchProgress);
                if (mIPlayControl != null) { 
                    //调用这个方法可以用进度条控制音频播放,传入的是一个百分比
                    mIPlayControl.seekTo(touchProgress);
                }
                isUserTouchProgress=false;
            }
        });
        mPlayOrPause.setOnClickListener(new View.OnClickListener() { 
            @Override
            public void onClick(View v) { 
                //播放或暂停
                if (mIPlayControl != null) { 
                    mIPlayControl.playOrPause();
                }
            }
        });
        mStop.setOnClickListener(new View.OnClickListener() { 
            @Override
            public void onClick(View v) { 
                //关闭按钮被点击了
                if (mIPlayControl != null) { 
                    mIPlayControl.stop();
                }
            }
        });

    }

    private void initView() { 
        mSeekBar = this.findViewById(R.id.seek_bar);
        mPlayOrPause = this.findViewById(R.id.play_or_pause);
        mStop = this.findViewById(R.id.stop);
    }

    @Override
    protected void onDestroy() { 
        super.onDestroy();

        if (mIsBind && mConnection != null) { 
            Log.d(TAG, "onDestroy...");
            //释放资源
            mIPlayControl.unregisterViewController();
            unbindService(mConnection);
            mIsBind = false;
        }
    }

    
    private IPlayViewControl mIPlayViewControl = new IPlayViewControl() { 
        @Override
        public void onPlayerStateChange(int state) { 
            //跟据播放状态来更新UI
            switch (state){ 
                case PLAYER_STATE_PLAY:
                    //播放状态的话要修改按钮显示成暂停
                    mPlayOrPause.setText("暂停");
                    break;
                case PLAYER_STATE_PAUSE:
                case PLAYER_STATE_STOP:
                    //暂停状态的话要修改按钮显示成播放
                    mPlayOrPause.setText("播放");
                    break;

            }

        }

        @Override
        public void onSeekChange(final float seek) { 
            //改变进度条更新,有一个条件,当用户手碰在进度条上就不更新,不然会抖动
            Log.d(TAG, "onSeekChange: -->"+seek);
            runOnUiThread(new Runnable() { 
                @Override
                public void run() { 
                    if (!isUserTouchProgress) { 
                        mSeekBar.setProgress((int)seek);
                    }
                }
            });

        }
    };
}

在Service中


public class PlayService extends Service { 
    private PlayerPresenter mPlayerPresenter;
    @Override
    public void onCreate() { 
        super.onCreate();
        if(mPlayerPresenter==null){ 
            //当mPlayerPresenter为空时创建,这是继承的Binder类
            mPlayerPresenter=new PlayerPresenter();
        }
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) { 
        //绑定之后返回一个IBinder类型
        return mPlayerPresenter;
    }

    @Override
    public void onDestroy() { 
        super.onDestroy();
        //服务销毁时将其置空
        mPlayerPresenter=null;
    }
}

在PlayerPresenter中

继承了Binder类同时实现了IPlayContol接口,因为这个唯一能够使Service跟Activity进行数据交换的桥梁。

首先实现方法

public class PlayerPresenter extends Binder implements IPlayControl { 
    private static final String TAG = "PlayerPresenter";
    //设置成成员变量控制UI
    private IPlayViewControl mIPlayViewControl;
    //设置初始播放状态为停止播放
    private int currentState = PLAYER_STATE_STOP;
    //定义一个播放器
    public MediaPlayer mMediaPlayer;
    //开启一个计时器
    private Timer mTimer;
    //开启一个任务
    private SeekTimeTask mSeekTimeTaskask;

    @Override
    public void registerViewController(IPlayViewControl iPlayViewControl) { 
        //获得UI控制权
        this.mIPlayViewControl = iPlayViewControl;
    }

    @Override
    public void unregisterViewController() { 
        mIPlayViewControl=null;
    }

    @Override
    public void playOrPause() { 
        Log.d(TAG,"playOrPause");
        if(currentState==PLAYER_STATE_STOP){ 
            //创建播放器
            initPlayer();
            //设置数据源
            try { 
                //按照流程,具体可以参考Android.cn搜索MediaPlayer
                mMediaPlayer.setDataSource("/mnt/sdcard/jay.mp3");
                mMediaPlayer.prepare();
                mMediaPlayer.start();
                //改变当前状态
                currentState=PLAYER_STATE_PLAY;
                startTimer();
            } catch (IOException e) { 
                e.printStackTrace();
            }
        }else if(currentState==PLAYER_STATE_PLAY){ 
            //如果当前状态是播放的我们就暂停
            if (mMediaPlayer != null) { 
                mMediaPlayer.pause();
                currentState=PLAYER_STATE_PAUSE;
                stopTimer();
            }
        }else if(currentState==PLAYER_STATE_PAUSE){ 
            //如果当前是暂停的我们就继续播放音乐
            if (mMediaPlayer != null) { 
                mMediaPlayer.start();
                currentState=PLAYER_STATE_PLAY;
                startTimer();
            }
        }
        //通知UI界面
        if (mIPlayViewControl != null) { 
            mIPlayViewControl.onPlayerStateChange(currentState);
        }

    }

    
    private void initPlayer() { 
        if (mMediaPlayer==null) { 
            mMediaPlayer = new MediaPlayer();
            //设置播放类型
            mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
        }
    }

    @Override
    public void stop() { 
        Log.d(TAG,"stop");
        //stop的时候要判断是否有在播放
        if (mMediaPlayer != null ) { 
            mMediaPlayer.stop();
            //更新播放状态和UI
            currentState=PLAYER_STATE_STOP;
            stopTimer();
            if (mIPlayViewControl != null) { 
                mIPlayViewControl.onPlayerStateChange(currentState);
            }
            //释放资源
            mMediaPlayer.release();
            mMediaPlayer=null;
        }
    }

    @Override
    public void seekTo(float seek) { 
        Log.d(TAG,"seekTo.."+seek);
        //0~100之间,需要做一个转换,得到的seek是一个百分比
        if (mMediaPlayer != null) { 
            int tarSeek = (int) (seek*1.0f/100 * mMediaPlayer.getDuration());
            mMediaPlayer.seekTo(tarSeek);
        }
    }

    
    private void startTimer(){ 
        if (mTimer == null) { 
            mTimer = new Timer();
        }
        if (mSeekTimeTaskask == null) { 
            mSeekTimeTaskask = new SeekTimeTask();
        }
        //把任务扔到计时器里面,在特定的延迟时间每500ms更新一次
        mTimer.schedule(mSeekTimeTaskask,0,500);
    }
    private void stopTimer(){ 
        if (mTimer != null) { 
            mTimer.cancel();
            mTimer=null;
        }
        if (mSeekTimeTaskask != null) { 
            mSeekTimeTaskask.cancel();
            mSeekTimeTaskask=null;
        }
    }
    //设定一个task放进Timer中,每隔一段时间进行一次
    private class SeekTimeTask extends TimerTask { 
        @Override
        public void run() { 
            if (mMediaPlayer != null && mIPlayViewControl!=null) { 
                //获取当前的播放进度
                int currentPosition = mMediaPlayer.getCurrentPosition();
                //Log.d(TAG, "current play position --->"+ currentPosition);
                //换算成占100里面的多少了(因为设置的进度条数值为100)
                float curPosition = currentPosition*1.0f / mMediaPlayer.getDuration()*100;
                Log.d(TAG,"curPosition--->"+curPosition);
               //设置进度条显示 
              mIPlayViewControl.onSeekChange(curPosition);
            }
        }
    }
}



 
打赏
 本文转载自:网络 
所有权利归属于原作者,如文章来源标示错误或侵犯了您的权利请联系微信13520258486
更多>最近资讯中心
更多>最新资讯中心
0相关评论

推荐图文
推荐资讯中心
点击排行
最新信息
新手指南
采购商服务
供应商服务
交易安全
关注我们
手机网站:
新浪微博:
微信关注:

13520258486

周一至周五 9:00-18:00
(其他时间联系在线客服)

24小时在线客服