Android官方架构分析(一)——todo‑mvp

前言

android-architecture是google官方推出的关于Android架构设计的开源项目,相当于为开发者提供了在Android APP架构设计方面的指南,所以学习价值不言而喻。

该项目展示了多种不同的架构概念和工具来实现相同的应用程序,这里我们将挑选其中一些经典的架构方式对其Demo进行源码分析。

这一篇,我们对标准MVP架构的todo‑mvp进行分析。

项目结构

android-architecture一系列Demo都实现了一个TODO-LIST项目,分为任务列表(tasks)、任务详情(taskdetail)、添加任务(addedittask)、任务统计(statistics)四个功能模块。

从下图分包情况也可以看出,todo‑mvp项目是按功能模块划分包名,清晰易懂。

image
  • addedittask:添加任务
  • data:主要对数据来源实现了封装
  • statistics:任务统计
  • taskdetail:任务详情
  • tasks:任务列表
  • util:帮助类
  • BasePresenter:Presenter基类
  • BaseView:View基类

架构思路

标准MVP架构有别于Android传统MVC架构最明显的地方在于,View与Model不发生联系,通过Presenter传递。而View不再承担逻辑功能,只负责显示视图页面,逻辑由Presenter进行处理。

image

在todo‑mvp项目中,每一个具体模块都由Model、Presenter、View三部分来实现。

  • Model:data包内的数据来源的封装实现类,分为本地来源和远程来源。
  • Presenter:由Activity创建Presenter实例对象。
  • View:由Activity创建,并由Fragment作为View的具体实现。
Android官方架构分析(一)——todo‑mvp_第1张图片
image

上图为官方给出的结构图,清晰的展示了MVP各部分的具体实现。

代码分析

在MVP模式中,每一个功能模块都由Model、Presenter、View组成,我们用addedittask模块来展示代码。

image

AddEditTaskContract类:

/**
 * This specifies the contract between the view and the presenter.
 */
public interface AddEditTaskContract {

    interface View extends BaseView {

        void showEmptyTaskError();

        void showTasksList();

        void setTitle(String title);

        void setDescription(String description);

        boolean isActive();
    }

    interface Presenter extends BasePresenter {

        void saveTask(String title, String description);

        void populateTask();

        boolean isDataMissing();
    }
}

Contract类作为View和presenter之间的协议,封装了View和Presenter接口。MVP模式下,分出View接口和Persenter接口主要是为了将View和Persenter通过接口的方式解耦,而Contract将两者封装到一起,又可以方便查找和修改。

View接口中封装了对页面展示绘制渲染等相关操作,Persenter接口中封装了对程序逻辑、对接Model等相关操作。View接口和Presenter接口又分别继承了BaseView和BasePresenter。

public interface BaseView {

    void setPresenter(T presenter);

}

BaseView中需要保持对Presenter的引用。

public interface BasePresenter {

    void start();

}

BasePresenter中的start方法主要用于一些初始化操作。

AddEditTaskActivity类中创建AddEditTaskPresenter实例:

    // Create the presenter
    mAddEditTaskPresenter = new AddEditTaskPresenter(
            taskId,
            Injection.provideTasksRepository(getApplicationContext()),
            addEditTaskFragment,
            shouldLoadDataFromRepo);

Activity在MVC模式下,需要承担View和Controller两者的职责,代码相当繁重。而在MVP模式下,不再承担过多的功能。创建Presenter时传入Model和View的实例,具体逻辑操作都由Presenter来负责。

Presenter

public class AddEditTaskPresenter implements AddEditTaskContract.Presenter,
        TasksDataSource.GetTaskCallback {
        
    @NonNull
    private final TasksDataSource mTasksRepository;

    @NonNull
    private final AddEditTaskContract.View mAddTaskView;

    @Nullable
    private String mTaskId;

    private boolean mIsDataMissing;

    /**
     * Creates a presenter for the add/edit view.
     *
     * @param taskId ID of the task to edit or null for a new task
     * @param tasksRepository a repository of data for tasks
     * @param addTaskView the add/edit view
     * @param shouldLoadDataFromRepo whether data needs to be loaded or not (for config changes)
     */
    public AddEditTaskPresenter(@Nullable String taskId, @NonNull TasksDataSource tasksRepository,
            @NonNull AddEditTaskContract.View addTaskView, boolean shouldLoadDataFromRepo) {
        mTaskId = taskId;
        mTasksRepository = checkNotNull(tasksRepository);
        mAddTaskView = checkNotNull(addTaskView);
        mIsDataMissing = shouldLoadDataFromRepo;

        mAddTaskView.setPresenter(this);    //将Presenter实例对象赋给View
    }

    @Override
    public void start() {
        if (!isNewTask() && mIsDataMissing) {
            populateTask();
        }
    }
        
    ...
    
}

AddEditTaskPresenter实现了AddEditTaskContract.Presenter接口,并在构造函数中获取了Model和View的实例,具体业务逻辑就是对这两个实例对象进行操作来实现。

mTasksRepository:相当于Model的实例对象,对数据操作的具体实现。

mAddTaskView:相当于View的实例对象,页面展示的具体实现。

start()方法中执行了对Model对象(mTasksRepository)赋值和初始化工作。

View

public class AddEditTaskFragment extends Fragment implements AddEditTaskContract.View {

    private AddEditTaskContract.Presenter mPresenter;
    
    @Override
    public void onResume() {
        super.onResume();
        mPresenter.start();
    }

    @Override
    public void setPresenter(@NonNull AddEditTaskContract.Presenter presenter) {
        mPresenter = checkNotNull(presenter);
    }
    
    ...
    
}

AddEditTaskFragment实现了AddEditTaskContract.View接口,通过setPresenter方法获得Presenter实例,在onResume方法中执行Presenter的初始化操作,而当View接收到触发事件时,由Presenter实例来负责响应逻辑。

Model

public class TasksRepository implements TasksDataSource {

    private static TasksRepository INSTANCE = null;

    private final TasksDataSource mTasksRemoteDataSource;

    private final TasksDataSource mTasksLocalDataSource;

    // Prevent direct instantiation.
    private TasksRepository(@NonNull TasksDataSource tasksRemoteDataSource,
                            @NonNull TasksDataSource tasksLocalDataSource) {
        mTasksRemoteDataSource = checkNotNull(tasksRemoteDataSource);
        mTasksLocalDataSource = checkNotNull(tasksLocalDataSource);
    }
    
    ...
    
}

TasksRepository作为Model层的实现类,实现了TasksDataSource接口,封装了本地数据和远程数据两种数据来源,通过TasksRepository实例对象可对数据接口做统一操作。

总结

MVP架构较之以前的MVC架构,在代码模块解耦方面表现更出色,并且解决了Activity责任繁杂的问题。

  • View:只负责显示、绘制、渲染等工作。
  • Model:负责数据操作,如数据库、网络数据、缓存等。
  • Presenter:作为View和Model的桥梁,并负责程序逻辑。

这篇博客是Android架构一系列博客的第一篇,而且是比较标准的MVP架构,看起来有些老调重弹。后续将逐步分析android-architecture中一些比较成熟的架构,并分析与标准MVP架构的优劣。

你可能感兴趣的:(Android官方架构分析(一)——todo‑mvp)