项目地址:https://github.com/googlesamples/android-architecture/tree/todo-mvp/
在第一篇说过,todo-mvp只是android-architecture项目的一个分支

项目结构

todo-mvp主要使用了mvp架构来实现,如图
匆忙拥挤repeat
图中的Repository就是数据源,即M,包括Local数据和Remote数据;Fragment为V;Activity中依赖了P,V(Fragment)与P相互依赖,P依赖了M(Repository),即P分离了M与V;当然有时我们不需要Fragment,那么可以直接使用Activity来作为V

项目的主要包结构及Base接口

(不含测试package):
Android 官方示例:android-architecture 学习笔记(二)之todo-mvp_第1张图片
除BaseView、BasePresenter两个接口,其他package都以业务功能来划分的:
addedittask —— 添加任务
data —— 数据源
statistics —— 任务统计
taskdetail —— 任务详情
tasks —— 任务列表
util —— 工具类

BaseView、BasePresenter两个接口:

public interface BaseView {    void setPresenter(T presenter);}public interface BasePresenter {    void start();}

数据源Model

先来看下data模块,即M
Android 官方示例:android-architecture 学习笔记(二)之todo-mvp_第2张图片

Task —— 它就是一个java bean
TasksDataSource —— Task数据操作的接口
TasksRepository —— 实现了TasksDataSource,依赖了TasksLocalDataSource、TasksRemoteDataSource,实现根据不同情形,获取Local或Remote的相关数据
TasksRemoteDataSource —— 远程数据,一般可能走网络,当然这里没有,只是模拟
TasksPersistenceContract —— 约定了数据库表字段
TasksDbHelper —— 数据库操作
TasksLocalDataSource —— 本地数据源

注:项目中默认只操作了Local数据,若也想操作Remote,只需要将TasksRepository中的属性mCacheIsDirty=true,即可

tasks模块分析

接下来挑一个业务模块分析一下(其它模块大同小异),比如tasks
Android 官方示例:android-architecture 学习笔记(二)之todo-mvp_第3张图片
ScrollChildSwipeRefreshLayout —— 这是一个自定义Layout,不用理会
TasksActivity —— Activity
TasksContract —— 契约接口(每个功能模块都有一个),约定了两个子接口View和Presenter,及各自的公共方法;分别实现BaseView、BasePresenter两个接口
TasksFilterType —— enum类,任务过滤类型
TasksFragment —— Fragment,实现TasksContract.View
TasksPresenter —— Presenter,实现TasksContract.Presenter

再来分析一个具体的业务功能,比如展示tasks列表
在TasksContract#Presenter中,有一个方法:

void loadTasks(boolean forceUpdate);

相应的TasksContract#View中,有一个方法:

void showTasks(List<Task> tasks);

看下TasksPresenter的相关的一些代码:

public class TasksPresenter implements TasksContract.Presenter {    private final TasksRepository mTasksRepository;    private final TasksContract.View mTasksView;    private TasksFilterType mCurrentFiltering = TasksFilterType.ALL_TASKS;    private boolean mFirstLoad = true;    public TasksPresenter(@NonNull TasksRepository tasksRepository, @NonNull TasksContract.View tasksView) {        mTasksRepository = checkNotNull(tasksRepository, "tasksRepository cannot be null");        mTasksView = checkNotNull(tasksView, "tasksView cannot be null!");        mTasksView.setPresenter(this);    }    @Override    public void start() {        loadTasks(false);    }    @Override    public void loadTasks(boolean forceUpdate) {        // Simplification for sample: a network reload will be forced on first load.        loadTasks(forceUpdate || mFirstLoad, true);        mFirstLoad = false;    }    private void loadTasks(boolean forceUpdate, final boolean showLoadingUI) {        if (showLoadingUI) {            mTasksView.setLoadingIndicator(true);        }        if (forceUpdate) {            mTasksRepository.refreshTasks();        }        // The network request might be handled in a different thread so make sure Espresso knows        // that the app is busy until the response is handled.        EspressoIdlingResource.increment(); // App is busy until further notice        mTasksRepository.getTasks(new TasksDataSource.LoadTasksCallback() {            @Override            public void onTasksLoaded(List tasks) {                List tasksToShow = new ArrayList();                // This callback may be called twice, once for the cache and once for loading                // the data from the server API, so we check before decrementing, otherwise                // it throws "Counter has been corrupted!" exception.                if (!EspressoIdlingResource.getIdlingResource().isIdleNow()) {                    EspressoIdlingResource.decrement(); // Set app as idle.                }                // We filter the tasks based on the requestType                for (Task task : tasks) {                    switch (mCurrentFiltering) {                        case ALL_TASKS:                            tasksToShow.add(task);                            break;                        case ACTIVE_TASKS:                            if (task.isActive()) {                                tasksToShow.add(task);                            }                            break;                        case COMPLETED_TASKS:                            if (task.isCompleted()) {                                tasksToShow.add(task);                            }                            break;                        default:                            tasksToShow.add(task);                            break;                    }                }                // The view may not be able to handle UI updates anymore                if (!mTasksView.isActive()) {                    return;                }                if (showLoadingUI) {                    mTasksView.setLoadingIndicator(false);                }                processTasks(tasksToShow);            }            @Override            public void onDataNotAvailable() {                // The view may not be able to handle UI updates anymore                if (!mTasksView.isActive()) {                    return;                }                mTasksView.showLoadingTasksError();            }        });    }    private void processTasks(List tasks) {        if (tasks.isEmpty()) {            // Show a message indicating there are no tasks for that filter type.            processEmptyTasks();        } else {            // Show the list of tasks            mTasksView.showTasks(tasks);            // Set the filter label's text.            showFilterLabel();        }    }}

从上,看出TasksPresenter依赖了TasksRepository、TasksContract.View,即P依赖了M和V;当loadTasks(boolean forceUpdate, final boolean showLoadingUI)被调用后,先从M中获取数据,再调用processTasks(List tasks),其内部调用mTasksView.showTasks(tasks)将数据显示在V上;最后还要说的一点是在TasksPresenter的构造方法中,mTasksView.setPresenter(this) 将P传递给了V

再来看下V如何通过P,来获取数据并显示
TasksFragment,即V的主要代码:

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();    }    @Override    public void onCreate(@Nullable Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        mListAdapter = new TasksAdapter(new ArrayList(0), mItemListener);    }    @Override    public void onResume() {        super.onResume();        mPresenter.start();    }    @Override    public void setPresenter(@NonNull TasksContract.Presenter presenter) {        mPresenter = checkNotNull(presenter);    }    @Nullable    @Override    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {        swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {            @Override            public void onRefresh() {                mPresenter.loadTasks(false);            }        });        return root;    }    @Override    public void showTasks(List tasks) {        mListAdapter.replaceData(tasks);        mTasksView.setVisibility(View.VISIBLE);        mNoTasksView.setVisibility(View.GONE);    }}

看TasksFragment的onResume()中,调用了mPresenter.start(),而mPresenter.start()中,就调用了TasksPresenter#loadTasks(false);TasksFragment的onCreateView()中还注册了一个监听回调,即下拉刷新时,也会调用TasksPresenter#loadTasks(false);

P和V的初始化在Activity中完成
TasksActivity的主要代码:

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();            ActivityUtils.addFragmentToActivity(                    getSupportFragmentManager(), tasksFragment, R.id.contentFrame);        }        // Create the presenter        mTasksPresenter = new TasksPresenter(                Injection.provideTasksRepository(getApplicationContext()), tasksFragment);        // Load previously saved state, if available.        if (savedInstanceState != null) {            TasksFilterType currentFiltering =                    (TasksFilterType) savedInstanceState.getSerializable(CURRENT_FILTERING_KEY);            mTasksPresenter.setFiltering(currentFiltering);        }    }}

至此,一条完整的MVP架构实现的业务链就分析完成了

更多相关文章

  1. Android8.1添加MTP数据同步操作
  2. android - SAX解析XML数据
  3. Android客户端向服务器端发送数据的流程(1)
  4. Android的数据存储之一------SharedPreferences
  5. Android数据绑定Data Binding初体验

随机推荐

  1. 不是我不写博客,是我不敢写
  2. Android自动化测试之Monkeyrunner从零开
  3. Android日记之2012/02/08——浅谈Timer
  4. 使用Intent Filter来响应隐式Intent
  5. Android(安卓)Jni用bitmap形式实现Image
  6. Android(安卓)关于Bitmap对象于内存管理
  7. s3c2410/2440(armv4t) 移植教程
  8. Android(安卓)应用开发笔记 - UI开发详解
  9. 关于 Android(安卓)中 Support 支持包(1)
  10. Android仿人人客户端(v5.7.1)——人人授权