Android Google MVP Demo TODO解讀

HCLXIDIAN發表於2019-02-22

今天週六抽時間把google的2個 MVP Demo看一下,寫篇文章記錄一下.

 先來看一下第一個最基礎的todo-mvp

下圖是Google MNP第一個Demo的架構圖,至於為什麼要使用Activity+Fragment,這裡是把Activity當做了控制器(Controllers),負責建立Frament和Presenter並連線他們。Activity和Repository之間的圓圈代表他們直接主要通過介面互動。

Android Google MVP Demo TODO解讀
Android Google MVP Demo TODO解讀Android Google MVP Demo TODO解讀

下面看原始碼

 可以看出是每一個介面都單獨在一個包裡面,Model層作為公共的模組在data包下

Android Google MVP Demo TODO解讀

BasePresenter中需要定義一些所有Presenter的基礎行為,Demo中定義一個start方法

Android Google MVP Demo TODO解讀

BaseView定義了設定Presenter的方法,每個View都需要有一個對應的Presenter.

Android Google MVP Demo TODO解讀

每個Fragment都會有一個契約類,用來定義具體的BaseView和Presenter介面,從這個契約類能後一眼看出Presenter和UI有什麼操作,比如TaskDetailContract中

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();
}

interface Presenter extends BasePresenter {

    void editTask();//編輯task

    void deleteTask();

    void completeTask();

    void activateTask();
}複製程式碼

 下面進入TaskDetailActivity 看一下

以下是OnCreate的程式碼片段,UI的就省略了,建立了Fragment並新增到Activity

   ActivityUtils.addFragmentToActivity(getSupportFragmentManager(),
            taskDetailFragment, R.id.contentFrame);
}

// Create the presenter
new TaskDetailPresenter(
        taskId,
        Injection.provideTasksRepository(getApplicationContext()),
        taskDetailFragment);複製程式碼

並且new了一個Presenter,把fragment和repository傳入presenter中,來看一下在TaskDetailPresenter裡做了什麼

public TaskDetailPresenter(@Nullable String taskId,
                           @NonNull TasksRepository tasksRepository,
                           @NonNull TaskDetailContract.View taskDetailView) {
    mTaskId = taskId;
    mTasksRepository = checkNotNull(tasksRepository, "tasksRepository cannot be null!");
    mTaskDetailView = checkNotNull(taskDetailView, "taskDetailView cannot be null!");

    mTaskDetailView.setPresenter(this);
}複製程式碼

    mTaskDetailView.setPresenter(this);很關鍵,將TaskDetailPresenter的引用傳給了fragment,並儲存了對應的view(taskDetailView),這樣V 和 P就相互儲存了對方的例項。

 mTasksRepository = checkNotNull(tasksRepository, "tasksRepository cannot be null!");
複製程式碼

  可以看到TaskDetailPresenter還儲存了Model層的一個引用mTasksRepository,如果需要去獲取一個Task就是利用mTasksRepository.getTask(int id);

   mTasksRepository從哪來的??其實在我們new presenter的時候構造並傳入的

// Create the presenter
new TaskDetailPresenter(
        taskId,
        Injection.provideTasksRepository(getApplicationContext()),
        taskDetailFragment);複製程式碼

  public static TasksRepository provideTasksRepository(@NonNull Context context) {

    checkNotNull(context);
    ToDoDatabase database = ToDoDatabase.getInstance(context);
    return TasksRepository.getInstance(FakeTasksRemoteDataSource.getInstance(),
            TasksLocalDataSource.getInstance(new AppExecutors(),
                    database.taskDao()));
}複製程式碼

  在構造TaskRepository的時候傳入了FakeTasksRemoteDataSource和TasksLocalDataSource的單例,,這2個都是提供資料的,都實現了getTask(int id)方法,分別從遠端和本地獲取,在TasksRepository中會根據情況來進行呼叫,如果本地資料來源獲取不到就從遠端資料來源獲取

@Override
public void getTask(@NonNull final String taskId, @NonNull final GetTaskCallback callback) {
    //從本地資料庫獲取
    mTasksLocalDataSource.getTask(taskId, new GetTaskCallback() {
        @Override
        public void onTaskLoaded(Task task) {
            // Do in memory cache update to keep the app UI up to date
         
            mCachedTasks.put(task.getId(), task);
            callback.onTaskLoaded(task);
        }

        @Override
        public void onDataNotAvailable() {
            //從遠端獲取
            mTasksRemoteDataSource.getTask(taskId, new GetTaskCallback() {
                @Override
                public void onTaskLoaded(Task task) {
                 
                    mCachedTasks.put(task.getId(), task);
                    callback.onTaskLoaded(task);
                }

                @Override
                public void onDataNotAvailable() {
                    callback.onDataNotAvailable();
                }
            });
        }
    });
}複製程式碼

獲取到資料之後便通過callback回到給presenter,然後在回撥裡呼叫View介面進行UI的顯示。

mTasksRepository.getTask(mTaskId, new TasksDataSource.GetTaskCallback() {
    @Override
    public void onTaskLoaded(Task task) {
        
            showTask(task);
     
    }複製程式碼

整個流程基本是這樣,來看一下時序圖

Android Google MVP Demo TODO解讀Android Google MVP Demo TODO解讀

    總結一下,首先Activity負責管理管理View和Presenter以及他們的連線,以及建立Model,讓Model和Presenter互相持有對方的引用,TaskRepository則負責資料來源的管理以及怎麼獲取,是否從快取中獲取還是本地資料庫或者遠端伺服器,相對於傳統的開發模式,Presenter極大的減輕了Activity的負擔,讓Activity只關注UI方面的顯示。

     程式碼雖然簡單,但是真正用在專案中我感覺不會這麼簡單,第一點疑問就是這麼一個demo工程就需要建立這麼多class,這樣的話在大專案中那會有多少class!

     Google提供的Demo只是一個樣本,實際使用中肯定要結合專案進行靈活架構調整

相關文章