一 官方文檔說明
概要
這個例子是很多實例變化的基礎(后續(xù)還有一些實例 )淀弹,是mvp模式的簡單實現(xiàn)巷嚣,它采用依賴注入的方式為用戶提供本地和遠程數(shù)據(jù)源的存儲庫锈死,用回調的方式進行異步任務的處理夕玩。
mvp 概要圖片
注意:在mvp結構中,view 被重載
- android.view.VIew 類將會被當作 “android view”
- view 接收來自解析器(presenter)的指令毯欣,被簡稱為 “view”
Fragments
使用 fragments的兩個原因
- 把Activity和fragment 分離 是非常適合實現(xiàn)mvp的,Activity 完全控制和連接view 和 presenters.
- 使用fragment 有利于平板或者多分辨率
概念
四個功能
- Tasks
- TaskDetails
- AddEditTask
- Statistics
每個功能都有
在view 和presenter之間都定義好了協(xié)議
Activity負責創(chuàng)建fragment和presenters
fragment 實現(xiàn)view 的接口
-
presenter 實現(xiàn) presenter接口
一般來說臭脓,業(yè)務邏輯執(zhí)行在presenter中酗钞,view 用來執(zhí)行android 的ui工作
view 大多數(shù)情況沒有業(yè)務邏輯,它主要將presenter的命令轉為ui操作来累,并監(jiān)聽用戶的操作傳遞給presenter.
規(guī)范接口 用于定義連接 view和presenters砚作。
程序運行
如圖所示 先就增加一個任務的操作進行代碼分享
代碼分析
AddEditTaskActiviy (增加任務的activity)
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.addtask_act); 、
// Set up the toolbar. 設置標題
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
ActionBar actionBar = getSupportActionBar();
actionBar.setDisplayHomeAsUpEnabled(true);
actionBar.setDisplayShowHomeEnabled(true);
// 1.創(chuàng)建fragment
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); }
// Create the presenter 2.創(chuàng)建 presenter
new AddEditTaskPresenter( taskId, Injection.provideTasksRepository(getApplicationContext()),
addEditTaskFragment);}
結合文檔和代碼嘹锁,再activity的oncreate方法中葫录,主要兩個操作
- 創(chuàng)建fragment
- 實例化 presenter
AddEditTaskFragment (View) 代碼
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
FloatingActionButton fab = (FloatingActionButton) getActivity().findViewById(R.id.fab_edit_task_done);
fab.setImageResource(R.drawable.ic_done);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mPresenter.saveTask(mTitle.getText().toString(), mDescription.getText().toString());
}
});
}
在 onActivityCreate中 實現(xiàn)了完成增加任務的按鈕,把用戶的操作傳遞給presenter
AddEditTaskFragment 實現(xiàn)了AddEditTaskContract.view接口
AddEditTaskContract 代碼
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 saveTask(String title, String description);
void populateTask();
}
}
這個就是文檔中說的 contract 協(xié)議 定義了view 的接口领猾,供view去實現(xiàn)里面的方法米同,定義了presenter接口供對應的presenter去實現(xiàn)骇扇。
BaseView 基view 因為所有的view都要關聯(lián)一個presenter
<pre><code> public interface BaseView<T> {
void setPresenter(T presenter);
}
</pre></code>
看完View層 ,再看P層
AddEditTaskPresenter (P 層代碼)
實現(xiàn)了 AddEditTaskContract.Presenter接口
構造方法
//三個參數(shù) 任務 id面粮,數(shù)據(jù)源少孝,關聯(lián)的view
public AddEditTaskPresenter(@Nullable String taskId, @NonNull TasksDataSource
tasksRepository,
@NonNull AddEditTaskContract.View addTaskView) {
mTaskId = taskId;
mTasksRepository = checkNotNull(tasksRepository);
mAddTaskView = checkNotNull(addTaskView);
//view 設置 presenter
mAddTaskView.setPresenter(this);
}
接下來看AddEditTaskFragment 中完成按鈕的點擊事件
<pre><code> mPresenter.saveTask(mTitle.getText().toString(), mDescription.getText().toString());
</pre></code>
也就是present的saveTask方法
@Override
public void saveTask(String title, String description) {
if (isNewTask()) {
createTask(title, description);
} else {
updateTask(title, description);
}}
直接看 createTask方法
private void createTask(String title, String description) {
//新建一個任務
Task newTask = new Task(title, description);
if (newTask.isEmpty()) {
mAddTaskView.showEmptyTaskError();
} else {
//保存數(shù)據(jù)
mTasksRepository.saveTask(newTask);
//通知view 層展示新的數(shù)據(jù) (前面文檔:view層通過接收present的指令)
mAddTaskView.showTasksList();
}}
AddEditTaskPresenter 還實現(xiàn)了 TasksDataSource.GetTaskCallback
TasksDataSource(M 層)
數(shù)據(jù)層的兩個方法
@Override
public void onTaskLoaded(Task task) {
// The view may not be able to handle UI updates anymore
if (mAddTaskView.isActive()) {
mAddTaskView.setTitle(task.getTitle());
mAddTaskView.setDescription(task.getDescription());
}}
@Override
public void onDataNotAvailable() {
// The view may not be able to handle UI updates anymore
if (mAddTaskView.isActive()) {
mAddTaskView.showEmptyTaskError();
}}
獲取數(shù)據(jù)的接口
/**
* Main entry point for accessing tasks data.
* <p> * For simplicity, only getTasks() and getTask() have callbacks. Consider adding callbacks to other
* methods to inform the user of network/database errors or successful operations.
* For example, when a new task is created, it's synchronously stored in cache but usually every
* operation on database or network should be executed in a different thread.
*/
public interface TasksDataSource {
interface LoadTasksCallback {
void onTasksLoaded(List<Task> tasks);
void onDataNotAvailable();
} interface GetTaskCallback {
void onTaskLoaded(Task task);
void onDataNotAvailable();
}
void getTasks(@NonNull LoadTasksCallback callback);
void getTask(@NonNull String taskId, @NonNull GetTaskCallback callback);
void saveTask(@NonNull Task task);
void completeTask(@NonNull Task task);
void completeTask(@NonNull String taskId);
void activateTask(@NonNull Task task);
void activateTask(@NonNull String taskId);
void clearCompletedTasks();
void refreshTasks();
void deleteAllTasks();
void deleteTask(@NonNull String taskId);}
MVP的好處
- 分離了視圖和業(yè)務邏輯,降低耦合
- 簡化了Activity 的代碼