Android实例——MVP
MVPMVP是什么?基于Activity、Service实现——播放器实例View层接口及实现Presenter层接口及实现View-Presenter桥梁MVP是什么?Model-View-Presenter三层分离架构基于Activity、Service实现——播放器实例View层接口及实现创建播放状态接口IPlayViewControl,P层处理完逻辑导致状态改变时用于通知UI更新publi
·
MVP
MVP是什么?
Model-View-Presenter架构,由MVC演化而来,相比于MVC,View与Model不再直接通信,两者之间的所有交互均发生在Presenter
- Model是数据模型层,负责数据的存储和管理
- View是UI显示层,负责从界面获取输入数据并更新系统处理后的数据
- Presenter是逻辑处理层,负责系统逻辑功能的处理,起到View和Model之间的桥梁作用
MVP应用
Activity(Fragment)组成View层含有对Presenter的引用,用于将UI输入的数据传递到逻辑层处理
IPresenter接口定义了系统功能,含有ICallback接口的引用实现对View层的回调,当页面需要更新时通知View层进行更新操作。
Presenter层实现了IPresenter接口,对Model层数据进行操作,实现具体的代码功能逻辑
基于Activity、Service实现——播放器实例
权限
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
activity_main.xml布局
布局有一个进度条和两个按钮(播放/暂停、停止)
<?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">
<SeekBar
android:id="@+id/progress"
android:max="100"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<Button
android:id="@+id/play_or_puase"
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>
View层接口及实现
创建播放状态回调接口,用于通知UI更新
public interface IPlayViewCallBack {
void onPlayStateChange(int state);
void onSeekChange(int seek);
}
Activity作为View层更新根据状态更新UI
- 通过bindService获取P层引用
- 将V层回调接口注册到P层
- V层通过点击事件将数据传给P层处理
- P层处理完数据后,利用回调返回结果让V层更新UI
public class MainActivity extends AppCompatActivity implements IPlayViewCallBack {
private static final String TAG = "MainActivity";
private SeekBar mSeekBar;
private Button mPlayOrPause;
private Button mStop;
private PlayConnection mPlayConnection;
private IPlayPresenter mPlayPresenter;
private boolean isUserTouchProgress;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
initEvent();
initService();
}
private void initService() {
startService(new Intent(this, PlayService.class));
Intent intent = new Intent(this, PlayService.class);
mPlayConnection = new PlayConnection();
bindService(intent, mPlayConnection, BIND_AUTO_CREATE);
}
private class PlayConnection implements ServiceConnection {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mPlayPresenter = (IPlayPresenter) service;
mPlayPresenter.registerCallback(MainActivity.this);
}
@Override
public void onServiceDisconnected(ComponentName name) {
mPlayPresenter = null;
}
}
private void initEvent() {
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();
if (mPlayPresenter != null) {
mPlayPresenter.seekTo(touchProgress);
}
isUserTouchProgress = false;
}
});
mPlayOrPause.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if ((ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED)) {
ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, 1);
}
if (mPlayPresenter != null) {
mPlayPresenter.playOrPause();
}
}
});
mStop.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (mPlayPresenter != null) {
mPlayPresenter.stop();
}
}
});
}
private void initView() {
mSeekBar = (SeekBar) findViewById(R.id.progress);
mPlayOrPause = (Button) findViewById(R.id.play_or_puase);
mStop = (Button) findViewById(R.id.stop);
}
@Override
protected void onDestroy() {
super.onDestroy();
mPlayPresenter.unregisterCallback();
unbindService(mPlayConnection);
mPlayConnection = null;
}
@Override
public void onPlayStateChange(int state) {
switch (state) {
case PLAY_STATE_PLAY:
mPlayOrPause.setText("暂停");
break;
case PLAY_STATE_PAUSE:
case PLAY_STATE_STOP:
mPlayOrPause.setText("播放");
break;
}
}
@Override
public void onSeekChange(int seek) {
Log.d(TAG, "Thread.currentThread().getName( = " + Thread.currentThread().getName());
Log.d(TAG, "seek = " + seek);
runOnUiThread(new Runnable() {
@Override
public void run() {
if (!isUserTouchProgress) {
mSeekBar.setProgress(seek);
}
}
});
}
}
Tips:
- isUserTouchProgress变量避免边拖动边更新引起抖动,当用户触摸时为true不更新进度条, 拖动完了先更新拖动进度,再置false让其自动更新播放进度
- onSeekChange不调用runOnUiThread也不会崩溃,因为Android允许progressBar和surface在子线程中更新
Presenter层接口及实现
创建播放控制接口,用来处理逻辑事件
public interface IPlayPresenter {
int PLAY_STATE_PLAY = 1;
int PLAY_STATE_PAUSE = 2;
int PLAY_STATE_STOP = 3;
void registerCallback(IPlayViewCallBack callBack);
void unregisterCallback();
void playOrPause();
void stop();
void seekTo(int seek);
}
PlayPresenter继承Binder实现IPlayPresenter,用于在服务中返回
public class PlayPresenterImpl extends Binder implements IPlayPresenter {
private static final String TAG = "PlayPresenterImpl";
private IPlayViewCallBack mCallback;
private int mCurrentState = PLAY_STATE_STOP;
private MediaPlayer mMediaPlayer;
private Timer mTimer;
private SeekTimeTask mSeekTimeTask;
@Override
public void registerCallback(IPlayViewCallBack callBack) {
this.mCallback = callBack;
}
@Override
public void unregisterCallback() {
mCallback = null;
}
@Override
public void playOrPause() {
if (mCurrentState == PLAY_STATE_STOP) {
try {
if (mMediaPlayer == null) {
mMediaPlayer = new MediaPlayer();
mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
}
mMediaPlayer.setDataSource("/sdcard/Music/1.mp3");
mMediaPlayer.prepare();
mMediaPlayer.start();
mCurrentState = PLAY_STATE_PLAY;
startTimer();
} catch (IOException e) {
e.printStackTrace();
}
} else if (mCurrentState == PLAY_STATE_PLAY) {
if (mMediaPlayer != null) {
mMediaPlayer.pause();
mCurrentState = PLAY_STATE_PAUSE;
stopTimer();
}
} else if (mCurrentState == PLAY_STATE_PAUSE) {
if (mMediaPlayer != null) {
mMediaPlayer.start();
mCurrentState = PLAY_STATE_PLAY;
startTimer();
}
}
if (mCallback != null) {
mCallback.onPlayStateChange(mCurrentState);
}
}
@Override
public void stop() {
if (mMediaPlayer != null && mMediaPlayer.isPlaying()) {
mMediaPlayer.stop();
mCurrentState = PLAY_STATE_STOP;
stopTimer();
if (mCallback != null) {
mCallback.onPlayStateChange(mCurrentState);
}
mMediaPlayer.release();
mMediaPlayer = null;
}
}
@Override
public void seekTo(int seek) {
if (mMediaPlayer != null) {
int targetSeek = (int) (seek * 1.0f / 100 * mMediaPlayer.getDuration());
mMediaPlayer.seekTo(targetSeek);
}
}
private void startTimer() {
if (mTimer == null) {
mTimer = new Timer();
}
if (mSeekTimeTask == null) {
mSeekTimeTask = new SeekTimeTask();
}
mTimer.schedule(mSeekTimeTask, 0, 1000);
}
private void stopTimer() {
if (mTimer != null) {
mTimer.cancel();
mTimer = null;
}
if (mSeekTimeTask != null) {
mSeekTimeTask.cancel();
mSeekTimeTask = null;
}
}
private class SeekTimeTask extends TimerTask {
@Override
public void run() {
if (mMediaPlayer != null) {
int currentPosition = mMediaPlayer.getCurrentPosition();
Log.d(TAG, "run: currentPosition = " + currentPosition);
Log.d(TAG, "run: mMediaPlayer.getDuration() = " + mMediaPlayer.getDuration());
int duration = (int) (currentPosition * 1.0f / mMediaPlayer.getDuration() * 100);
Log.d(TAG, "run: duration = " + duration);
if (mCallback != null) {
mCallback.onSeekChange(duration);
}
}
}
}
}
Tips:
- 创建SeekTimeTask开启线程获取当前进度,传入Timer每隔1000ms更新进度条
View-Presenter桥梁
将View层和Presenter层通过Service绑定返回
public class PlayService extends Service {
private PlayPresenterImpl mPlayPresenterImpl;
@Override
public void onCreate() {
super.onCreate();
if (mPlayPresenterImpl == null) {
mPlayPresenterImpl = new PlayPresenterImpl();
}
}
@Override
public IBinder onBind(Intent intent) {
return mPlayPresenterImpl;
}
@Override
public void onDestroy() {
super.onDestroy();
mPlayPresenterImpl = null;
}
}
点击阅读全文
更多推荐
目录
所有评论(0)