亚洲国产日韩欧美一区二区三区,精品亚洲国产成人av在线,国产99视频精品免视看7,99国产精品久久久久久久成人热,欧美日韩亚洲国产综合乱

Android MVP 試水

Original 2016-11-02 16:01:38 714
abstract:還記得一年前,在上一家公司的時候,領導準備接一個案子,客戶那邊給了一份開發(fā)規(guī)范的文檔,上面明確的寫著要采用MVP模式進行開發(fā)。一開始看到這個模式時候,一臉懵逼,什么是MVP?不懂,問一下同事,也沒有人能說清楚,無奈那就百度吧。好簡單粗暴的說明啊,還是一臉懵逼。 后來,不知道為什么案子也沒有接,就這樣不了了之了。最近發(fā)生了很多事,從上一家公司離職,與朋友準備搞公司,搞了差不多2個月,到現(xiàn)在

還記得一年前,在上一家公司的時候,領導準備接一個案子,客戶那邊給了一份開發(fā)規(guī)范的文檔,上面明確的寫著要采用MVP模式進行開發(fā)。一開始看到這個模式時候,一臉懵逼,什么是MVP?不懂,問一下同事,也沒有人能說清楚,無奈那就百度吧。

1.png

好簡單粗暴的說明啊,還是一臉懵逼。 后來,不知道為什么案子也沒有接,就這樣不了了之了。

最近發(fā)生了很多事,從上一家公司離職,與朋友準備搞公司,搞了差不多2個月,到現(xiàn)在的從團隊退出。然后準備找工作。。。。

在這期間搞項目的時候,就抽空研究了一下MVP模式,試著用它進行開發(fā)。因為只是一個項目,涉及的還不深,所以叫試水。記錄一下。

網上關于MVP的介紹、講解、示例以及開源的項目很多,我這里就不廢話了,如果現(xiàn)在還有人不了解什么是MVP,那就百度去吧。我這里參考Google的源碼todo-mvp來說。 先看一下目錄結構: 

1.png

不要問我為什么我截圖的字體顏色是藍色的,我不會告訴你我是用的octotree瀏覽器插件。 這里有兩個Base文件:BaseView、BasePresenter,好像和VP有關,先看一下源碼:

package com.example.android.architecture.blueprints.todoapp;

public interface BasePresenter {

void start();

}


package com.example.android.architecture.blueprints.todoapp;

public interface BaseView<T> {

void setPresenter(T presenter);

}

What ?這是什么鬼?兩個接口?干嗎用的?不知道,不明覺厲。不管了,反正一個對應的V,一個對應的是P就是了。好吧,你們估計再說我這不廢話了。這里看不出什么東西,那就從程序的入口看吧,從AndroidManifest.xml中找到程序的入口是tasks/TasksActivity。

<activity
  android:name="com.example.android.architecture.blueprints.todoapp.tasks.TasksActivity"
  android:theme="@style/AppTheme.OverlapSystemBar">
  <intent-filter>
    <action android:name="android.intent.action.MAIN" />
    <category android:name="android.intent.category.LAUNCHER" />
   </intent-filter>
 </activity>

打開tasks包,看到如下幾個文件

1.png

我的習慣是先不看里面的內容,先看文件名字,大致了解每個文件是干嘛用的,這樣有助于對整體進行把控,所以這里就體現(xiàn)了命名規(guī)范的重要性,關于命名規(guī)范,可以百度,也可以參考我的另外一篇文章:Android 開發(fā)規(guī)范(個人版)。哎呀,又扯遠了,繼續(xù)回來看代碼。

第一個文件,應該是個自定義的布局,好像沒什么太大的關系。 第二個主程序的入口,沒啥說的。 第三個Contract (契約),誰和誰的,不懂,先不管。 第四個Filter Type(過濾器類型),應該是一些類型的定義,好像關系也不大,先不管。 第五個Fragment,不說了 第六個Persenter,這個有關系,而且還很大,那就先看一下它吧。

public class TasksPresenter implements TasksContract.Presenter {
   ....  private final TasksContract.View mTasksView; 
  public TasksPresenter(@NonNull TasksRepository   tasksRepository, @NonNull TasksContract.View tasksView) {
  ...
  mTasksView = checkNotNull(tasksView, "tasksView cannot be null!"); 
  mTasksView.setPresenter(this);
  }  @Override
  public void start() {
  ...
  }
}

省略了一下不必要的代碼,這里可以看到幾個關鍵點, 1、TasksPresenter本身實現(xiàn)了TasksContract.Presenter; 2、構造函數(shù)里面需要傳入一個TasksContract.View; 3、拿到這個tasksView后賦值給了mTasksView,并把自己通過mTasksView.setPresenter(this)方法傳遞出去。

到這里算是有點眉目了。知道了P和V是如何綁定在一起的了。 P綁定V:通過實例化是傳入V; V綁定P: 通過v.setPresenter(P);

但如何使用V呢?繼續(xù)往下,這里用到了TasksContract這個契約,跟蹤一下代碼看一下。

package com.example.android.architecture.blueprints.todoapp.tasks;

package com.example.android.architecture.blueprints.todoapp.tasks;
import android.support.annotation.NonNull;
import com.example.android.architecture.blueprints.todoapp.BaseView;
import com.example.android.architecture.blueprints.todoapp.data.Task;
import com.example.android.architecture.blueprints.todoapp.BasePresenter;
import java.util.List;

/**
 * 這指定 view 和 presenter 之間的 contract。
 * This specifies the contract between the view and the presenter.
 */

public interface TasksContract {
  interface View extends BaseView<Presenter> {
      void setLoadingIndicator(boolean active);
      void showTasks(List<Task> tasks);
      void showAddTask();
      void showTaskDetailsUi(String taskId);
      void showTaskMarkedComplete();
      void showTaskMarkedActive();
      void showCompletedTasksCleared();
      void showLoadingTasksError();
      void showNoTasks();
      void showActiveFilterLabel();
      void showCompletedFilterLabel();
      void showAllFilterLabel();
      void showNoActiveTasks();
      void showNoCompletedTasks();
      void showSuccessfullySavedMessage();
      boolean isActive();
      void showFilteringPopUpMenu();
  }

  interface Presenter extends BasePresenter {
      void result(int requestCode, int resultCode);
      void loadTasks(boolean forceUpdate);
      void addNewTask();
      void openTaskDetails(@NonNull Task requestedTask);
      void completeTask(@NonNull Task completedTask);
      void activateTask(@NonNull Task activeTask);
      void clearCompletedTasks();
      void setFiltering(TasksFilterType requestType);
      TasksFilterType getFiltering();
  }
}

看到這里就有點意思了,契約類里面主要做了兩件事,

定義了一個繼承自BaseView的接口(View), 并聲明需要實現(xiàn)的方法。

定義一個繼承自BasePresenter的接口并繼承(Presenter),并聲明需要實現(xiàn)的方法。

其實也可以說是一件事,就是聲明一些接口。

哦,這下知道Contract是干嗎用的了,就是把V、P的接口寫到同一個文件里面啊,好像也并么有什么高大上的東西???那我把這個文件分成兩個文件寫,應該也可以吧?我認為是可以的。但是又基于Contract的含義即:契約,就是把View和Presenter綁定到一起:

interface Presenter extends BasePresenter {}
interface View extends BaseView<Presenter> {}

這樣還是按照官方的來,用一個文件來寫好了。

Presenter找到了,Contract也知道是干嗎用的了。那么View呢,從文件名已經找不到了,那就看繼續(xù)看代碼吧。從TasksActivity看起,首先我們知道TasksPresenter構造函數(shù)里面有一個TasksContract.View的參數(shù),那么就找這個參數(shù)傳的什么。

public class TasksActivity extends AppCompatActivity { 
    ....
    private TasksPresenter mTasksPresenter;

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

     TasksFragment tasksFragment =
     (TasksFragment) getSupportFragmentManager().findFragmentById(R.id.contentFrame);
     if (tasksFragment == null) {
     // Create the fragment 
     tasksFragment = TasksFragment.newInstance();
    }
    .....

    // Create the presenter 
    //這個傳入的是 tasksFragment
    mTasksPresenter = new TasksPresenter(
    Injection.provideTasksRepository(getApplicationContext()), tasksFragment);

   } 
  .......
}

由上面的代碼可知,TasksPresenter 傳入了一個TasksFragment的對象,那這樣的TasksFragment就應該是所謂的View了,跟蹤進入TasksFragment。

public class TasksFragment extends Fragment implements TasksContract.View {private TasksContract.Presenter mPresenter;

......public TasksFragment() {// Requires empty public constructor}public static TasksFragment newInstance() {return new TasksFragment();
}

......@Overridepublic void onResume() {super.onResume();
mPresenter.start();
}@Overridepublic void setPresenter(@NonNull TasksContract.Presenter presenter) {
mPresenter = checkNotNull(presenter);
}
....@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container,

Bundle savedInstanceState) {
.....
}
.......

}

果然,TasksFragment 實現(xiàn)了TasksContract.View,就是所謂的View。他的核心點在于: 1、實現(xiàn)了TasksContract.View; 2、重寫setPresenter方法,接收傳遞過來的presenter。

這樣之后,就可以通過presenter.xxxxx()的方式來調用presenter里面定義的一些方法,而presenter里面定義的方法主要執(zhí)行耗時操作或者一些數(shù)據(jù)處理等等,等到presenter里面的函數(shù)執(zhí)行完畢之后,在通過mTasksView.xxx()的方式回調給TasksFragment,TasksFragment再進行頁面的改變。

官方給的Demo就看到這里吧,因為關于MVP核心的東西差不多就看完了,或許還有更多的東西我沒有發(fā)掘。

根據(jù)官方Demo,我這里總結了一下實現(xiàn)MVP模式的步驟:

1、定義BaseView、BasePresenter??梢詤⒖脊俜绞纠?2、定義契約類,在里面定義兩個接口,舉個登錄的例子:

public interface LoginContract {   interface Presenter extends BasePresenter {      /**
       * 登錄
       */
      void login();
   }   interface View extends BaseView<Presenter> {      /** 
        * 返回登錄成功
       */
      void loginSuccess();      void loginFailed(String errorMessage);
   }
}

3、定義一個實現(xiàn)契約類中Presenter接口的類,用于實現(xiàn)邏輯代碼,并把處理結果返回。例如:

public class LoginPresenter implements LoginContract.Presenter {   private LoginContract.View view;   public LoginPresenter(LoginContract.View view) {      this.view = view;
      view.setPresenter(this);
   }   /**
    * 登錄
    */
   @Override
   public void login() {
      String useName = view.getUserName();
      String pwd = view.getPwd();
      Map<String, String> params = new HashMap<String, String>();
      params.put("phone", useName);
      params.put("password", pwd);
      AuthRequestUtil.doLogin(params, User.class, new ResponseCallBack<User>() {         @Override
         public void onSuccess(User data) {            super.onSuccess(data);
            saveLoginInfo(data);            //返回登錄成功
            view.loginSuccess();
         }         @Override
         public void onFailure(ServiceException e) {            super.onFailure(e);            //返回登錄失敗
            view.loginFailed(e.getMessage());
         }
      });
   }
}

4、在Activity 或者Fragment中實現(xiàn)契約類中的View接口。

要實現(xiàn)簡單的MVP,差不多就這4步。接觸的時間也不長,中間有可能會出現(xiàn)一些紕漏或者錯誤,如果有這方面的牛人在看到這篇文章的時候,希望能給出寶貴意見。這里先說聲謝謝。

關于MVP,還有很多東西,我看到還有關Presenter生命周期的相關文章,還沒有仔細研究。這里先記一下。等有時間在仔細研究一下。


Release Notes

Popular Entries