落花踏尽游何处,笑入胡姬酒肆中。这篇文章主要讲述Android 官方示例:android-architecture 学习笔记之todo-mvp相关的知识,希望能为你提供帮助。
【Android 官方示例(android-architecture 学习笔记之todo-mvp)】项目地址:
https://github.com/googlesamples/android-architecture/tree/todo-mvp/
在第一篇说过,
todo-mvp只是android-architecture项目的一个分支
项目结构
todo-mvp主要使用了mvp架构来实现,
如图
![Android 官方示例(android-architecture 学习笔记之todo-mvp)](http://img.readke.com/220416/0130295132-0.png)
文章图片
图中的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)](http://img.readke.com/220416/01302a438-1.jpg)
文章图片
除BaseView、BasePresenter两个接口, 其他package都以业务功能来划分的:
addedittask —— 添加任务
data —— 数据源
statistics —— 任务统计
taskdetail —— 任务详情
tasks —— 任务列表
util —— 工具类
BaseView、BasePresenter两个接口:
public interface BaseView<
T>
{
void setPresenter(T presenter);
}
public interface BasePresenter {
void start();
}
数据源Model
先来看下data模块, 即M
![Android 官方示例(android-architecture 学习笔记之todo-mvp)](http://img.readke.com/220416/0130293433-2.jpg)
文章图片
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)](http://img.readke.com/220416/0130293328-3.jpg)
文章图片
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 noticemTasksRepository.getTasks(new TasksDataSource.LoadTasksCallback() {
@
Override
public void onTasksLoaded(List<
Task>
tasks) {
List<
Task>
tasksToShow =
new ArrayList<
Task>
();
// 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<
Task>
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<
Task>
(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<
Task>
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架构实现的业务链就分析完成了
推荐阅读
- Android深入源码分析理解Aidl整体调用流程(雷惊风)
- Android之Activity系列总结--任务和返回栈
- 解决sdk更新时候报错 http://dl-ssl.google.com/android上不去,链接拒绝
- 电脑没有音频设备怎样办,图文详细说明电脑没有音频设备怎样处理
- 谷歌浏览器怎样设置首页,图文详细说明谷歌浏览器怎样设置首页
- 无法加载插件,图文详细说明怎样处理浏览器显示无法加载插件
- 电脑分辨率低,图文详细说明电脑分辨率低怎样办
- excel词典xllex.dll文件失去或损坏,图文详细说明excel词典xllex.dll文件失去或损坏怎样处理
- 出错代码0xc004e003,图文详细说明怎样处理出错代码0xc004e003