google官方mvp demo的地址:
https://github.com/googlesamples/android-architecture/tree/todo-mvp/
下面对这个demo进行分析
先看一下\app\src\main\java目录结构
每一个页面都有一个文件夹,其中包括4个主要的类
Activity 管理Fragment, 建立Fragment和对应的Presenter之间的关系
Constract 定义View和Presenter接口
Fragment 只负责显示View。要进行什么操作,就调用Presenter中的对应的方法。
Presenter 处理各种逻辑,然后调用Framgnet中的操作View的方法,进行相应的显示。
下面对任务详情模块,也就是taskdetail文件夹进行分析
首先是STaskDetailActivity关键代码
public class TaskDetailActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
//添加TaskDetailFragment
TaskDetailFragment taskDetailFragment = (TaskDetailFragment) getSupportFragmentManager()
.findFragmentById(R.id.contentFrame);
if (taskDetailFragment == null) {
taskDetailFragment = TaskDetailFragment.newInstance(taskId);
ActivityUtils.addFragmentToActivity(getSupportFragmentManager(),
taskDetailFragment, R.id.contentFrame);
}
// new TaskDetailPresenter对象,传入一个值,tasksRepository,和taskDetailFragment
new TaskDetailPresenter(taskId,Injection.provideTasksRepository(getApplicationContext()),taskDetailFragment);
}
}
TaskDetailPresenter类
public interface TaskDetailContract {
//定义View接口,也就是要对View进行的操作,需要的数据会在参数中传入
interface View extends BaseView<Presenter> {
void setLoadingIndicator(boolean active);
void showMissingTask();
void hideTitle();
void showTitle(String title);
void hideDescription();
void showDescription(String description);
void showCompletionStatus(boolean complete);
void showEditTask(String taskId);
void showTaskDeleted();
void showTaskMarkedComplete();
void showTaskMarkedActive();
boolean isActive();
}
//定义Presenter接口,就是要进行的操作
interface Presenter extends BasePresenter {
void editTask();
void deleteTask();
void completeTask();
void activateTask();
}
}
TaskDetailPresenter类关键代码
public class TaskDetailPresenter implements TaskDetailContract.Presenter {
public TaskDetailPresenter(@Nullable String taskId, @NonNull TasksRepository tasksRepository, @NonNull TaskDetailContract.View taskDetailView) {
this.mTaskId = taskId;
//拿到TasksRepository
mTasksRepository = checkNotNull(tasksRepository, "tasksRepository cannot be null!");
//拿到TaskDetailFragment继承的View接口,这样就可以操作fragment中的View了
mTaskDetailView = checkNotNull(taskDetailView, "taskDetailView cannot be null!");
//将这个TaskDetailPresenter实例,传入到View接口中,也就是传到fragment中
mTaskDetailView.setPresenter(this);
}
//BasePresent中的类,开始调用Presenter的方法
@Override
public void start() {
openTask();
}
private void openTask() {
//根据mTaskId,调用fragment中操作view的方法
if (null == mTaskId || mTaskId.isEmpty()) {
mTaskDetailView.showMissingTask();
return;
}
//调用fragment中操作view的方法
mTaskDetailView.setLoadingIndicator(true);
//通过mTasksRepository获取数据,根据结果调用fragment中操作view的方法
mTasksRepository.getTask(mTaskId, new TasksDataSource.GetTaskCallback() {
@Override
public void onTaskLoaded(Task task) {
if (!mTaskDetailView.isActive()) {
return;
}
mTaskDetailView.setLoadingIndicator(false);
if (null == task) {
mTaskDetailView.showMissingTask();
} else {
showTask(task);
}
}
@Override
public void onDataNotAvailable() {
if (!mTaskDetailView.isActive()) {
return;
}
mTaskDetailView.showMissingTask();
}
});
}
}
TaskDetailFragment类中关键代码
public class TaskDetailFragment extends Fragment implements TaskDetailContract.View {
//这里的mPresenter,在Activity中new TaskDetailPresenter的时,已经被初始化了
//也就是TaskDetailPresente的构造函数中调用mTaskDetailView.setPresenter(this)方法时
//也就是本类中的setPresenter方法
private TaskDetailContract.Presenter mPresenter;
@Override
public void onResume() {
super.onResume();
//页面打开时,调用mPresenter.start()方法
mPresenter.start();
}
//初始化当前的mPresenter
@Override
public void setPresenter(@NonNull TaskDetailContract.Presenter presenter) {
mPresenter = checkNotNull(presenter);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_delete:
//调用mPresenter中的方法
mPresenter.deleteTask();
return true;
}
return false;
}
//操作view
@Override
public void hideTitle() {
mDetailTitle.setVisibility(View.GONE);
}
//操作view
@Override
public void showTitle(String title) {
mDetailTitle.setVisibility(View.VISIBLE);
mDetailTitle.setText(title);
}
//操作view
@Override
public void showMissingTask() {
mDetailTitle.setText("");
mDetailDescription.setText(getString(R.string.no_data));
}
}
上面介绍mvp中的View和Presenter,关于moudle,他是用来操作数据的,由Presenter调用,封装起来,好用就行。下面看一下这个demo中moudle是怎么封装的
在TaskDetailActivity中,调用了Injection类,这个类的作用就是获得一个模块的仓库实例
public class Injection {
//获得TasksRepository实例,同时在TasksRepository初始化远程数据源(接口)和本地存储数据源
public static TasksRepository provideTasksRepository(@NonNull Context context) {
checkNotNull(context);
return TasksRepository.getInstance(FakeTasksRemoteDataSource.getInstance(), TasksLocalDataSource.getInstance(context));
}
}
那么Prensent要怎么获取数据呢?比如在TaskDetailPresenter类中
mTasksRepository.getTask(mTaskId, new TasksDataSource.GetTaskCallback() {
@Override
public void onTaskLoaded(Task task) {
}
@Override
public void onDataNotAvailable() {
}
});
再看TasksRepository类中的getTask方法
public void getTask(@NonNull final String taskId, @NonNull final GetTaskCallback callback) {
checkNotNull(taskId);
checkNotNull(callback);
if (cachedTask != null) {
callback.onTaskLoaded(cachedTask);
return;
}
//先获取本地数据
mTasksLocalDataSource.getTask(taskId, new GetTaskCallback() {
@Override
public void onTaskLoaded(Task task) {
callback.onTaskLoaded(task);
}
@Override
public void onDataNotAvailable() {
mTasksRemoteDataSource.getTask(taskId, new GetTaskCallback() {
//本地数据获取不到,获取远程数据,也就是访问接口
@Override
public void onTaskLoaded(Task task) {
callback.onTaskLoaded(task);
}
@Override
public void onDataNotAvailable() {
callback.onDataNotAvailable();
}
});
}
});
}
其中mTasksLocalDataSource,mTasksRemoteDataSource都是TasksDataSource接口定义的,在Activity中调用Injection方法初始化的。下面分别看一下TasksDataSource接口的实现类TasksRemoteDataSource和TasksLocalDataSource。
public class TasksRemoteDataSource implements TasksDataSource {
@Override
public void getTask(@NonNull String taskId, final @NonNull GetTaskCallback callback) {
final Task task = TASKS_SERVICE_DATA.get(taskId);
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
@Override
public void run() {
callback.onTaskLoaded(task);
}
}, SERVICE_LATENCY_IN_MILLIS);
}
}
public class TasksLocalDataSource implements TasksDataSource {
@Override
public void getTask(@NonNull String taskId, @NonNull GetTaskCallback callback) {
SQLiteDatabase db = mDbHelper.getReadableDatabase();
String[] projection = {
TaskEntry.COLUMN_NAME_ENTRY_ID,
TaskEntry.COLUMN_NAME_TITLE,
TaskEntry.COLUMN_NAME_DESCRIPTION,
TaskEntry.COLUMN_NAME_COMPLETED
};
String selection = TaskEntry.COLUMN_NAME_ENTRY_ID + " LIKE ?";
String[] selectionArgs = { taskId };
Cursor c = db.query(
TaskEntry.TABLE_NAME, projection, selection, selectionArgs, null, null, null);
Task task = null;
if (c != null && c.getCount() > 0) {
c.moveToFirst();
String itemId = c.getString(c.getColumnIndexOrThrow(TaskEntry.COLUMN_NAME_ENTRY_ID));
String title = c.getString(c.getColumnIndexOrThrow(TaskEntry.COLUMN_NAME_TITLE));
String description = c.getString(c.getColumnIndexOrThrow(TaskEntry.COLUMN_NAME_DESCRIPTION));
boolean completed = c.getInt(c.getColumnIndexOrThrow(TaskEntry.COLUMN_NAME_COMPLETED)) == 1;
task = new Task(title, description, itemId, completed);
}
if (c != null) {
c.close();
}
db.close();
if (task != null) {
callback.onTaskLoaded(task);
} else {
callback.onDataNotAvailable();
}
}
}
好啦,代码终于看完了!
我觉得mvp最大的好处是,适合于多人开发一个项目。这样对项目的结果也有了一套明确的规范,增加了代码的可读性和可维护性。并且Activity,Fragment只负责显示View就好,有什么操作都交给了Presenter,Presenter的代码量其实也没有那么多,数据处理都是moudle层做的,他负责回调得到数据就好了。moudle层什么都不用关心,就是处理数据。 这样每个模块的的代码都很少,很简洁,特别是Activity,Fragment看起来无比的清爽,瞬间开心的感觉有木有。