android音乐播放器(mvp架构)
1.最終效果
功能:播放、暫停、停止、可拖動進度條等。
個人建議有一定基礎看本篇博客。
為了條理清晰易于學習,代碼只針對最主要的功能,可自行進行擴展。
沒有對代碼進行過多的闡述,可以先將功能實現之后,再根據代碼梳理思路。
2.思路及流程
3.總的目錄結構
4.定義接口
4.1播放器控制接口
我們的view層持有IPlayerControlPresenter接口,可以調用其方法來進行業務邏輯的處理,面向接口編程可以使系統獲得良好的擴展性。
public interface IPlayerControlPresenter {/*** 注冊回調接口* @param iPlayerViewControlCallback*/void registerCallback(IPlayerViewControlCallback iPlayerViewControlCallback);/*** 取消注冊回調接口*/void unRegisterCallback();/*** 播放* @param assets*/void playOrPause(AssetManager assets);/*** 停止播放*/void stop();/*** 設置進度條* @param seek*/void setSeek(int seek); }4.2ui更新回調接口
可以讓view實現這個回調接口,或者是new一個匿名內部類。
public interface IPlayerViewControlCallback {/*** 播放進度改變* @param state*/void playStateChange(int state);/*** 進度條改變* @param seek*/void seekChange(int seek); }5.編寫頁面布局文件
<?xml version="1.0" encoding="utf-8"?> <LinearLayout 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"android:orientation="vertical"tools:context=".MainActivity"><SeekBarandroid:layout_width="match_parent"android:layout_height="wrap_content"android:padding="10dp"android:id="@+id/seek_bar"/><LinearLayoutandroid:layout_width="match_parent"android:gravity="center"android:layout_height="wrap_content"><Buttonandroid:layout_width="wrap_content"android:layout_height="match_parent"android:text="播放"android:layout_margin="10dp"android:id="@+id/play"/><Buttonandroid:layout_width="wrap_content"android:layout_height="match_parent"android:layout_margin="10dp"android:text="關閉"android:id="@+id/close"/></LinearLayout></LinearLayout>6.創建一個service文件
onBind方法會在服務綁定的時候返回一個binder,我們可以讓PlayerControlPresenterImpl類繼承自Binder類并且實現IPlayerControlPresenter接口。
public class PlayerService extends Service {public PlayerService() {}private PlayerControlPresenterImpl playerControlPresenter;@Overridepublic void onCreate() {super.onCreate();if (playerControlPresenter == null) {playerControlPresenter = new PlayerControlPresenterImpl();}}@Overridepublic IBinder onBind(Intent intent) {return playerControlPresenter;}@Overridepublic void onDestroy() {super.onDestroy();playerControlPresenter = null;} }7.view層activity
服務綁定成功并且返回的binder不為空的時候,onServiceConnected方法會被調用。iPlayerViewControlCallback 即是接口IPlayerViewControlCallback的實現。初始化對應的監聽事件。
public class MainActivity extends AppCompatActivity {private static final String TAG = "MainActivity";private SeekBar seekBar;private Button playOrPause,close;private IPlayerControlPresenter iPlayerControlPresenter;private boolean isUserHandTouch = false;private ServiceConnection serviceConnection = new ServiceConnection() {@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {//服務連接成功Log.d(TAG,"service connect success");iPlayerControlPresenter = (IPlayerControlPresenter) service;iPlayerControlPresenter.registerCallback(iPlayerViewControlCallback);}@Overridepublic void onServiceDisconnected(ComponentName name) {iPlayerControlPresenter = null;}};private IPlayerViewControlCallback iPlayerViewControlCallback = new IPlayerViewControlCallback() {@Overridepublic void playStateChange(int state) {switch (state) {case State.PLAYER_STATE_PLAY:playOrPause.setText("暫停");break;case State.PLAYER_STATE_PAUSE:case State.PLAYER_STATE_STOP:playOrPause.setText("播放");break;}}@Overridepublic void seekChange(int seek) {runOnUiThread(new Runnable() {@Overridepublic void run() {if(!isUserHandTouch) {seekBar.setProgress(seek);}}});}};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);initView();initService();initEvent();}private void initView() {seekBar = findViewById(R.id.seek_bar);playOrPause = findViewById(R.id.play);close = findViewById(R.id.close);}private void initService() {Log.d(TAG,"initService方法被調用");Intent intent = new Intent(this, PlayerService.class);startService(intent);bindService(intent,serviceConnection,BIND_AUTO_CREATE);}private void initEvent() {seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {@Overridepublic void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {}@Overridepublic void onStartTrackingTouch(SeekBar seekBar) {isUserHandTouch = true;}@Overridepublic void onStopTrackingTouch(SeekBar seekBar) {isUserHandTouch = false;int progress = seekBar.getProgress();Log.d(TAG,"當前的進度條數值為:" + progress);if(iPlayerControlPresenter != null && !isUserHandTouch) {iPlayerControlPresenter.setSeek(progress);}}});playOrPause.setOnClickListener(v -> {if(iPlayerControlPresenter != null) {AssetManager assets = getAssets();iPlayerControlPresenter.playOrPause(assets);}});close.setOnClickListener(v -> {if(iPlayerControlPresenter != null) {iPlayerControlPresenter.stop();}});}@Overrideprotected void onDestroy() {super.onDestroy();if (iPlayerControlPresenter != null) {iPlayerControlPresenter.unRegisterCallback();//解綁服務unbindService(serviceConnection);}} }8.導入歌曲
首先創建assets目錄,必須創建在app/src/main這個目錄下面,也就是和java、res
這兩個目錄是平級的。右擊app/src/main——>New——>Directory,在彈出的對話框中輸入"assets",目錄創建完成。歌曲下載推薦在 http://tool.liumingye.cn/music/?page=homePage ,特別好用。
9.定義播放狀態
public interface State {int PLAYER_STATE_PLAY = 1;int PLAYER_STATE_PAUSE = 2;int PLAYER_STATE_STOP = 3; }10.編寫邏輯具體實現
推薦閱讀代碼,或者先將功能實現再閱讀。
public class PlayerControlPresenterImpl extends Binder implements IPlayerControlPresenter {private static final String TAG = "PlayerControlPresenter";private IPlayerViewControlCallback iPlayerViewControlCallback;private int currentState = State.PLAYER_STATE_STOP;private MediaPlayer mediaPlayer;private Timer timer;private SeekTimeTask timeTask;@Overridepublic void registerCallback(IPlayerViewControlCallback iPlayerViewControlCallback) {this.iPlayerViewControlCallback = iPlayerViewControlCallback;}@Overridepublic void unRegisterCallback() {this.iPlayerViewControlCallback = null;}@Overridepublic void playOrPause(AssetManager assets) {if(currentState == State.PLAYER_STATE_STOP) {initPlayer(assets);mediaPlayer.start();currentState = State.PLAYER_STATE_PLAY;startTimer();}else if(currentState == State.PLAYER_STATE_PLAY) {mediaPlayer.pause();currentState = State.PLAYER_STATE_PAUSE;stopTimer();}else if(currentState == State.PLAYER_STATE_PAUSE) {mediaPlayer.start();currentState = State.PLAYER_STATE_PLAY;startTimer();}iPlayerViewControlCallback.playStateChange(currentState);}private void initPlayer(AssetManager assets) {mediaPlayer = new MediaPlayer();try {AssetFileDescriptor fd = assets.openFd(SongNames.SUNNY_DAY);mediaPlayer.setDataSource(fd.getFileDescriptor(),fd.getStartOffset(),fd.getLength());mediaPlayer.prepare();} catch (IOException e) {e.printStackTrace();}}@Overridepublic void stop() {if (mediaPlayer != null) {currentState = State.PLAYER_STATE_STOP;mediaPlayer.stop();mediaPlayer.release();iPlayerViewControlCallback.playStateChange(currentState);iPlayerViewControlCallback.seekChange(0);stopTimer();}}@Overridepublic void setSeek(int seek) {Log.d(TAG,"進度條數值為:" + seek);if (mediaPlayer != null) {int targetSeek = (int) (seek * 1f / 100 * mediaPlayer.getDuration());mediaPlayer.seekTo(targetSeek);}else if(currentState == State.PLAYER_STATE_STOP){iPlayerViewControlCallback.seekChange(0);}}private void startTimer() {if(timer == null) {timer = new Timer();}if(timeTask == null) {timeTask = new SeekTimeTask();}timer.schedule(timeTask,0,500);}private void stopTimer() {if(timeTask != null) {timeTask.cancel();timeTask = null;}if(timer != null) {timer.cancel();timer = null;}}private class SeekTimeTask extends TimerTask {@Overridepublic void run() {if (mediaPlayer != null && iPlayerViewControlCallback != null) {int currentPosition = mediaPlayer.getCurrentPosition();int duration = mediaPlayer.getDuration();int nowPosition = (int) (currentPosition * 1f / duration * 100);iPlayerViewControlCallback.seekChange(nowPosition);}}} }總結
使用mvp架構可以很好地解耦,并且代碼十分清晰,雖說現在普遍使用mvvm架構,但是mvp架構確實是很適合學習的架構。
總結
以上是生活随笔為你收集整理的android音乐播放器(mvp架构)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: (转载)悟透JavaScript
- 下一篇: B2B直销商城