MVP之Android官方MVP架構(gòu)學(xué)習(xí)—View層和Presenter層

一、 MVC和MVP

1. MVC

MVC的全稱為Model-View-Controller,即模型-視圖-控制器。

  • Model:處理數(shù)據(jù)和業(yè)務(wù)邏輯等
  • View:顯示界面,展示結(jié)果等
  • Controller:控制流程,處理交互

MVC各個(gè)模塊通信方式如下:

MVC.jpg

2. MVP

MVP的全稱為Model-View-Presenter,即模型-視圖-協(xié)調(diào)器(主持者)

  • Model:處理數(shù)據(jù)和業(yè)務(wù)邏輯等
  • View:顯示界面,展示結(jié)果等
  • Presenter:協(xié)調(diào)Model和View模塊工作,處理交互

MVP各個(gè)模塊通信方式如下:

MVP.jpg

3. MVC和MVP區(qū)別

  • 在MVC模式中,View和Model可以直接交互;在MVP模式中,View和Model模塊不能直接交互,View通過(guò)Presenter與Model間接交互。

  • 在MVC中,Controller是基于行為的,可以被多個(gè)View共享,可以負(fù)責(zé)決定顯示哪個(gè)View;在MVP中View和Presenter是一對(duì)一或這一對(duì)多的,并且Presenter和View是通過(guò)接口交互的。

二、 Google官方MVP示例

1. 項(xiàng)目說(shuō)明

項(xiàng)目地址:https://github.com/googlesamples/android-architecture

項(xiàng)目?jī)?nèi)容說(shuō)明:

已完成的示例

進(jìn)行中的示例

2. todo-mvp基礎(chǔ)架構(gòu)項(xiàng)目分析

2.1 代碼組織方式

項(xiàng)目的app/src/main/java目錄中代碼的組織方式是按照功能模塊組織的,每個(gè)功能為一個(gè)包,每個(gè)功能模塊的內(nèi)部分為xActivity、xFragment、xPresenter、xContract四個(gè)類文件,其作用如下:

  • xActivity主要負(fù)責(zé)創(chuàng)建View和Presenter實(shí)例,并將它們聯(lián)系起來(lái)
  • xFragment實(shí)現(xiàn)View接口,作為MVP結(jié)構(gòu)中的View
  • xPresenter實(shí)現(xiàn)Presenter接口,是MVP結(jié)構(gòu)中的Presenter
  • xContract作為合同接口,統(tǒng)一管理View和Presenter的接口,便于查看和維護(hù)View和Presenter的功能

Model作為單獨(dú)的模塊存放與data目錄下

項(xiàng)目的app/src/main/java目錄中結(jié)構(gòu)如下:

todo-mvp-java.jpg
2.2 MVP實(shí)現(xiàn)方式

以添加或編輯任務(wù)功能模塊(addedittask)為例

2.2.1 View和Present基礎(chǔ)接口
  • BaseView接口中有setPresenter方法,用于將Presenter實(shí)例傳入View中,在Presenter的實(shí)現(xiàn)類的構(gòu)造方法中調(diào)用。
public interface BaseView<T> {

    void setPresenter(T presenter);

}
  • BasePresenter接口中有start方法,用于Presenter開(kāi)始獲取數(shù)據(jù)并調(diào)用View進(jìn)行界面顯示,在View的實(shí)現(xiàn)類Fragment中的onResume方法中調(diào)用。
public interface BasePresenter {

    void start();

}
2.2.2 AddEditTaskContract

AddEditTaskContract是一個(gè)合同接口,其中包含了View和Presenter接口,便于查看和維護(hù)View和Presenter的功能。

public interface AddEditTaskContract {

    interface View extends BaseView<Presenter> {

        void showEmptyTaskError();

        void showTasksList();

        void setTitle(String title);

        void setDescription(String description);

        boolean isActive();
    }

    interface Presenter extends BasePresenter {

        void createTask(String title, String description);

        void updateTask( String title, String description);

        void populateTask();
    }
}
2.2.3 AddEditTaskActivity

AddEditTaskActivity中創(chuàng)建了View的實(shí)現(xiàn)類AddEditTaskFragment的實(shí)例和Presenter的實(shí)現(xiàn)類AddEditTaskPresenter的實(shí)例,并把它們聯(lián)系起來(lái)。

public class AddEditTaskActivity extends AppCompatActivity {
    ...

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.addtask_act);

        ...

        // 創(chuàng)建AddEditTaskFragment實(shí)例
        AddEditTaskFragment addEditTaskFragment =
                (AddEditTaskFragment) getSupportFragmentManager().findFragmentById(R.id.contentFrame);
        String taskId = null;
        if (addEditTaskFragment == null) {
            addEditTaskFragment = AddEditTaskFragment.newInstance();
            if(getIntent().hasExtra(AddEditTaskFragment.ARGUMENT_EDIT_TASK_ID)) {
                taskId = getIntent().getStringExtra(
                        AddEditTaskFragment.ARGUMENT_EDIT_TASK_ID);
                actionBar.setTitle(R.string.edit_task);
                Bundle bundle = new Bundle();
                bundle.putString(AddEditTaskFragment.ARGUMENT_EDIT_TASK_ID, taskId);
                addEditTaskFragment.setArguments(bundle);
            } else {
                actionBar.setTitle(R.string.add_task);
            }
            ActivityUtils.addFragmentToActivity(getSupportFragmentManager(),
                    addEditTaskFragment, R.id.contentFrame);
        }

        // 創(chuàng)建Presenter實(shí)例,傳入Model實(shí)例和AddEditTaskFragment實(shí)例,建立View和Presenter之間的聯(lián)系
        new AddEditTaskPresenter(
                taskId,
                Injection.provideTasksRepository(getApplicationContext()),
                addEditTaskFragment);
    }

    ...
}
2.2.4 AddEditTaskFragment

AddEditTaskFragment實(shí)現(xiàn)了AddEditTaskContract接口中的View接口,其中有一個(gè)Presenter實(shí)例,在onResume方法中調(diào)用Presenter的start方法。

public class AddEditTaskFragment extends Fragment implements AddEditTaskContract.View {

    private AddEditTaskContract.Presenter mPresenter;

    public static AddEditTaskFragment newInstance() {
        return new AddEditTaskFragment();
    }

    public AddEditTaskFragment() {
        // Required empty public constructor
    }

    @Override
    public void onResume() {
        super.onResume();
        // 調(diào)用start方法
        mPresenter.start();
    }

    // 重寫(xiě)setPresenter方法
    @Override
    public void setPresenter(@NonNull AddEditTaskContract.Presenter presenter) {
        mPresenter = checkNotNull(presenter);
    }

    ...
}
2.2.5 AddEditTaskPresenter

AddEditTaskPresenter實(shí)現(xiàn)了AddEditTaskContract接口中的Presenter接口,其中有一個(gè)View實(shí)例,在構(gòu)造方法中調(diào)用View的setPresenter方法與View建立聯(lián)系。

public class AddEditTaskPresenter implements AddEditTaskContract.Presenter,
        TasksDataSource.GetTaskCallback {

    // Model實(shí)例,完成數(shù)據(jù)獲取  
    @NonNull
    private final TasksDataSource mTasksRepository;

    @NonNull
    private final AddEditTaskContract.View mAddTaskView;

    @Nullable
    private String mTaskId;

    public AddEditTaskPresenter(@Nullable String taskId, @NonNull TasksDataSource tasksRepository,
            @NonNull AddEditTaskContract.View addTaskView) {
        mTaskId = taskId;
        mTasksRepository = checkNotNull(tasksRepository);
        mAddTaskView = checkNotNull(addTaskView);

        mAddTaskView.setPresenter(this);
    }

    // 重寫(xiě)start方法,開(kāi)始獲取數(shù)據(jù)
    @Override
    public void start() {
        if (mTaskId != null) {
            populateTask();
        }
    }

    ...
}
3. 總結(jié)

官方的實(shí)例項(xiàng)目有十分清晰的模塊劃分,復(fù)雜度也相對(duì)較低,易于學(xué)習(xí),相對(duì)于普通的MVP增加了合同接口,便于模塊功能的管理和擴(kuò)展。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容