学习googlesample demo之安卓架构mvp的正确姿势以及个人分析源码心得

本文主要是介绍学习googlesample demo之安卓架构mvp的正确姿势以及个人分析源码心得,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

谈到mvp,我先说说我以前是如何封装刷新 翻页等等的吧.

另外我在没研究mvp之前写的刷新可控制是否加载更多是查询是否是更多 以及需要创建的适配器等等虽然不是接口,但是感觉也实现了一个刷新逻辑的共用
创建一个p,然后把操作接口传递进去传递进去 ,再activity的onCreate() new出这个p 然后activity实现接口方法 接口方法也包含了模型的查询,数据的查询也是在p层操作,但是具体请求地址是啥,地址成功之后的数据类型结果的返回还是通过申明的接口,
直接附上代码吧,各位说说这都叫什么模式,这都是我想出来的共用。
mvp把是完全的接口了,我这mvp又不像mvc也不像,传说中的4不像?但是我的确解决了不同类型无法改变的结类的 如activity fragment 共用一个逻辑,只需要复写这些重新定义即可,但是内部的核心还是那些。

public abstract class BaseJSONRefreshActivityN<ADAPTER extends RecyclerView.Adapter> extends BaseActionBarActivity implements BaseJSONRefreshLogicI<ADAPTER> {public JSONRefreshRefreshWrap<ADAPTER> getRefreshWrap() {return refreshWrap;}private JSONRefreshRefreshWrap<ADAPTER> refreshWrap;@Overrideprotected final void init(Bundle savedInstanceState) {refreshWrap = new JSONRefreshRefreshWrap<ADAPTER>() {@Overrideprotected List parseJsonResult(String json) {return BaseJSONRefreshActivityN.this.parseJsonResult(json);}@Overridepublic RecyclerView getRecyclerView() {return BaseJSONRefreshActivityN.this.getRecyclerView();}public  String getInterceptEmptyDataTip(){return BaseJSONRefreshActivityN.this.getInterceptEmptyDataTip();}public boolean isInterceptEmptyData(){return BaseJSONRefreshActivityN.this.isInterceptEmptyData();}@Overridepublic void onParseSucc(List list) {BaseJSONRefreshActivityN.this.onParseSucc(list);}@Overridepublic SmartRefreshLayout getSwipyRefreshLayout() {return (SmartRefreshLayout) BaseJSONRefreshActivityN.this.getSwipyRefreshLayout();}@Overridepublic void onInitStart() {BaseJSONRefreshActivityN.this.onInitStart();}@Overridepublic void onInitFinish() {BaseJSONRefreshActivityN.this.onInitFinish();}@Overridepublic RecyclerView.LayoutManager onCreateLayoutManager() {return BaseJSONRefreshActivityN.this.onCreateLayoutManager();}@Overridepublic ADAPTER onCreateAdapter() {return BaseJSONRefreshActivityN.this.onCreateAdapter();}@Overridepublic String getUrl(int page) {return BaseJSONRefreshActivityN.this.getUrl(page);}@Overridepublic boolean autoLoad() {return BaseJSONRefreshActivityN.this.autoLoad();}@Overridepublic boolean enableLoadMore() {return BaseJSONRefreshActivityN.this.enableLoadMore();}@Overrideprotected boolean needEmptyView() {return BaseJSONRefreshActivityN.this.needEmptyView();}};refreshWrap.init();}}

我突然觉得,我这里应该直接 把activity 的BaseJSONRefreshLogicI传递过去,而不是通过复写匿名类的方法接控制外部类,不过坏处就是所有逻辑都要复写,我这里只是针对性的复写一些。

另外,我这叫啥子写法,是一套解决点赞 等+1 -1的封装

public interface IOperaAction {public int getAction();public void setAction(int isfollow);//
}
public static void addAction(Activity activity, final String function, String addUrl, String deleteUrl, final IOperaAction action) {if (!AppContext.isLogin()) {ActionEngine.toLoginActivity(activity);return;}if (deleteUrl == null && action.getAction() == 1) {ToastUtils.showToast("已经添加" + function + "了");return;}final String cannel = action.getAction() == 1 ? "取消" : "";HttpUtil.queryData(activity, action.getAction() == 0 ? addUrl : deleteUrl, true, new NetQuestTask.SimpleRequestDataListener() {@Overridepublic void onSuccess(String str) {ResultBean resultBean = JSON.parseObject(str, ResultBean.class);if (resultBean.getResoures() == 1) {action.setAction(action.getAction() == 1 ? 0 : 1);//ToastUtils.showToast(cannel + function + "成功");} else {ToastUtils.showToast(cannel + function + "失败");}}@Overridepublic void onFail(String str) {ToastUtils.showToast(cannel + function + "失败 服务器错误 " + str);}});}
//实际上服务器有时候不弄累加值得,这里贴的没有自动给+1 -1的,但是可以解决多个地方不同接口的点赞
image.png
image.png

好了,不说这个了

开始正文

打开项目是不是就只会一个一个zip包下载?多累啊,
其实仔细点开链接发现地址前缀是同一个,于是焕然大悟,难怪谷歌也说推荐git clone
首先要学习git的朋友看看我写的这篇文章http://qssq666.cn/2016/08/26/%E5%AD%A6%E4%B9%A0git%E5%BF%83%E5%BE%97/

git clone https://github.com/googlesamples/android-architecture.git  qssq-lean-android-architecture
cd qssq-lean-android-architecture

刚进去只能看到几个文档md的,需要切换分支。
查看该项目所有分支

git branch -a
image.png

切换分支演示git checkout todo-mvp 当然我这里是切换到另外一个分支,git branch查看当前所处哪个分支,会发现当前分支颜色是不相同的 其实我是从master->todo-mvp->todo-mvp-rxjava的,上面的图已经暴露我的操作行踪了,尴尬不

image.png

再详细一点点

image.png

git branch -l 查看本地分支git branch -r 查看远程分支

image.png

好,git就只需要掌握着几个就差不多了,开始学习了,下次见

2018-4-21 21:35:12

2018-4-22 00:33:21 继续

todo-mvp

随便找一个mvp的界面案例分析就够了,实际上这个demo是每一个activity就会搞一个mvp结构,我觉得吧,似乎没多大必要,除非是一个成功的产品,真的没必要各种 ,顶多来一套刷新机制的mvp

除非有很多共用性的东西,我觉得我的QQ机器人的添加数据界面是可以这么架构,我之前是用的mvc继承来做这件事情的


TasksRepository实现类实现了接口TasksDataSource数据源 称之为M

StatisticsContract.View扩展接口继承了接口BaseView接口则是这是是V,

在官方的项目中,所有activity界面都会包含一个对应逻辑的android fragment,所以由这个fragment实现StatisticsContract.View进行view的显示隐藏等操作

StatisticsPresenter实现类实现了接口StatisticsContract.Presenter接口则是这是是P,

下面Persenter的具体代码,可以看出来p掌控了v,也掌控了m,
先上个图再看代码

image.png

从图上可以看出view箭头反过来指向了persenter,那么可以从 mStatisticsView.setPresenter(this)就可以证明的确它是要这么做了,不传递 Persenter进去难道隔空传物不成?,对不,那么下面是Presenter的代码了
public class StatisticsPresenter implements StatisticsContract.Presenter {private final TasksRepository mTasksRepository;private final StatisticsContract.View mStatisticsView;public StatisticsPresenter(@NonNull TasksRepository tasksRepository,@NonNull StatisticsContract.View statisticsView) {mTasksRepository = checkNotNull(tasksRepository, "tasksRepository cannot be null");mStatisticsView = checkNotNull(statisticsView, "StatisticsView cannot be null!");mStatisticsView.setPresenter(this);}@Overridepublic void start() {loadStatistics();}private void loadStatistics() {mStatisticsView.setProgressIndicator(true);EspressoIdlingResource.increment(); // App is busy until further noticemTasksRepository.getTasks(new TasksDataSource.LoadTasksCallback() {@Overridepublic void onTasksLoaded(List<Task> tasks) {int activeTasks = 0;int completedTasks = 0;if (!EspressoIdlingResource.getIdlingResource().isIdleNow()) {EspressoIdlingResource.decrement(); // Set app as idle.}// We calculate number of active and completed tasksfor (Task task : tasks) {if (task.isCompleted()) {completedTasks += 1;} else {activeTasks += 1;}}// The view may not be able to handle UI updates anymoreif (!mStatisticsView.isActive()) {return;}mStatisticsView.setProgressIndicator(false);mStatisticsView.showStatistics(activeTasks, completedTasks);}@Overridepublic void onDataNotAvailable() {if (!mStatisticsView.isActive()) {return;}mStatisticsView.showLoadingStatisticsError();}});}
}

再看看实现v,通过这个代码就能理解为什么view箭头指向````Persenter```

public class StatisticsFragment extends Fragment implements StatisticsContract.View {private TextView mStatisticsTV;private StatisticsContract.Presenter mPresenter;public static StatisticsFragment newInstance() {return new StatisticsFragment();}@Overridepublic void setPresenter(@NonNull StatisticsContract.Presenter presenter) {mPresenter = checkNotNull(presenter);}@Nullable@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {View root = inflater.inflate(R.layout.statistics_frag, container, false);mStatisticsTV = (TextView) root.findViewById(R.id.statistics);return root;}@Overridepublic void onResume() {super.onResume();mPresenter.start();}@Overridepublic void setProgressIndicator(boolean active) {if (active) {mStatisticsTV.setText(getString(R.string.loading));} else {mStatisticsTV.setText("");}}@Overridepublic void showStatistics(int numberOfIncompleteTasks, int numberOfCompletedTasks) {if (numberOfCompletedTasks == 0 && numberOfIncompleteTasks == 0) {mStatisticsTV.setText(getResources().getString(R.string.statistics_no_tasks));} else {String displayString = getResources().getString(R.string.statistics_active_tasks) + " "+ numberOfIncompleteTasks + "\n" + getResources().getString(R.string.statistics_completed_tasks) + " " + numberOfCompletedTasks;mStatisticsTV.setText(displayString);}}@Overridepublic void showLoadingStatisticsError() {mStatisticsTV.setText(getResources().getString(R.string.statistics_error));}@Overridepublic boolean isActive() {return isAdded();}
}

从上面代码体现了2个信息
非fragment本身的@Override 实际上是p控制v的过程
而fragment也调用了mPresenter.start() 实际上是反过来控制Persenterstart()实际上是间接让Persenter去控制M 进行加载数据
所以 图片看懂了。。。

M的逻辑

public class TasksRepository implements TasksDataSource {private static TasksRepository INSTANCE = null;private final TasksDataSource mTasksRemoteDataSource;private final TasksDataSource mTasksLocalDataSource;boolean mCacheIsDirty = false;private TasksRepository(@NonNull TasksDataSource tasksRemoteDataSource,@NonNull TasksDataSource tasksLocalDataSource) {mTasksRemoteDataSource = checkNotNull(tasksRemoteDataSource);mTasksLocalDataSource = checkNotNull(tasksLocalDataSource);}public static TasksRepository getInstance(TasksDataSource tasksRemoteDataSource,TasksDataSource tasksLocalDataSource) {if (INSTANCE == null) {INSTANCE = new TasksRepository(tasksRemoteDataSource, tasksLocalDataSource);}return INSTANCE;}public static void destroyInstance() {INSTANCE = null;}@Overridepublic void getTasks(@NonNull final LoadTasksCallback callback) {checkNotNull(callback);// Respond immediately with cache if available and not dirtyif (mCachedTasks != null && !mCacheIsDirty) {callback.onTasksLoaded(new ArrayList<>(mCachedTasks.values()));return;}if (mCacheIsDirty) {// If the cache is dirty we need to fetch new data from the network.getTasksFromRemoteDataSource(callback);} else {// Query the local storage if available. If not, query the network.mTasksLocalDataSource.getTasks(new LoadTasksCallback() {@Overridepublic void onTasksLoaded(List<Task> tasks) {refreshCache(tasks);callback.onTasksLoaded(new ArrayList<>(mCachedTasks.values()));}@Overridepublic void onDataNotAvailable() {getTasksFromRemoteDataSource(callback);}});}}@Overridepublic void saveTask(@NonNull Task task) {checkNotNull(task);mTasksRemoteDataSource.saveTask(task);mTasksLocalDataSource.saveTask(task);// Do in memory cache update to keep the app UI up to dateif (mCachedTasks == null) {mCachedTasks = new LinkedHashMap<>();}mCachedTasks.put(task.getId(), task);}@Overridepublic void completeTask(@NonNull Task task) {checkNotNull(task);mTasksRemoteDataSource.completeTask(task);mTasksLocalDataSource.completeTask(task);Task completedTask = new Task(task.getTitle(), task.getDescription(), task.getId(), true);// Do in memory cache update to keep the app UI up to dateif (mCachedTasks == null) {mCachedTasks = new LinkedHashMap<>();}mCachedTasks.put(task.getId(), completedTask);}@Overridepublic void completeTask(@NonNull String taskId) {checkNotNull(taskId);completeTask(getTaskWithId(taskId));}@Overridepublic void activateTask(@NonNull Task task) {checkNotNull(task);mTasksRemoteDataSource.activateTask(task);mTasksLocalDataSource.activateTask(task);Task activeTask = new Task(task.getTitle(), task.getDescription(), task.getId());// Do in memory cache update to keep the app UI up to dateif (mCachedTasks == null) {mCachedTasks = new LinkedHashMap<>();}mCachedTasks.put(task.getId(), activeTask);}@Overridepublic void activateTask(@NonNull String taskId) {checkNotNull(taskId);activateTask(getTaskWithId(taskId));}@Overridepublic void clearCompletedTasks() {mTasksRemoteDataSource.clearCompletedTasks();mTasksLocalDataSource.clearCompletedTasks();// Do in memory cache update to keep the app UI up to dateif (mCachedTasks == null) {mCachedTasks = new LinkedHashMap<>();}Iterator<Map.Entry<String, Task>> it = mCachedTasks.entrySet().iterator();while (it.hasNext()) {Map.Entry<String, Task> entry = it.next();if (entry.getValue().isCompleted()) {it.remove();}}}@Overridepublic void getTask(@NonNull final String taskId, @NonNull final GetTaskCallback callback) {checkNotNull(taskId);checkNotNull(callback);Task cachedTask = getTaskWithId(taskId);if (cachedTask != null) {callback.onTaskLoaded(cachedTask);return;}mTasksLocalDataSource.getTask(taskId, new GetTaskCallback() {@Overridepublic void onTaskLoaded(Task task) {// Do in memory cache update to keep the app UI up to dateif (mCachedTasks == null) {mCachedTasks = new LinkedHashMap<>();}mCachedTasks.put(task.getId(), task);callback.onTaskLoaded(task);}@Overridepublic void onDataNotAvailable() {mTasksRemoteDataSource.getTask(taskId, new GetTaskCallback() {@Overridepublic void onTaskLoaded(Task task) {// Do in memory cache update to keep the app UI up to dateif (mCachedTasks == null) {mCachedTasks = new LinkedHashMap<>();}mCachedTasks.put(task.getId(), task);callback.onTaskLoaded(task);}@Overridepublic void onDataNotAvailable() {callback.onDataNotAvailable();}});}});}@Overridepublic void refreshTasks() {mCacheIsDirty = true;}@Overridepublic void deleteAllTasks() {mTasksRemoteDataSource.deleteAllTasks();mTasksLocalDataSource.deleteAllTasks();if (mCachedTasks == null) {mCachedTasks = new LinkedHashMap<>();}mCachedTasks.clear();}@Overridepublic void deleteTask(@NonNull String taskId) {mTasksRemoteDataSource.deleteTask(checkNotNull(taskId));mTasksLocalDataSource.deleteTask(checkNotNull(taskId));mCachedTasks.remove(taskId);}private void getTasksFromRemoteDataSource(@NonNull final LoadTasksCallback callback) {mTasksRemoteDataSource.getTasks(new LoadTasksCallback() {@Overridepublic void onTasksLoaded(List<Task> tasks) {refreshCache(tasks);refreshLocalDataSource(tasks);callback.onTasksLoaded(new ArrayList<>(mCachedTasks.values()));}@Overridepublic void onDataNotAvailable() {callback.onDataNotAvailable();}});}private void refreshCache(List<Task> tasks) {if (mCachedTasks == null) {mCachedTasks = new LinkedHashMap<>();}mCachedTasks.clear();for (Task task : tasks) {mCachedTasks.put(task.getId(), task);}mCacheIsDirty = false;}private void refreshLocalDataSource(List<Task> tasks) {mTasksLocalDataSource.deleteAllTasks();for (Task task : tasks) {mTasksLocalDataSource.saveTask(task);}}@Nullableprivate Task getTaskWithId(@NonNull String id) {checkNotNull(id);if (mCachedTasks == null || mCachedTasks.isEmpty()) {return null;} else {return mCachedTasks.get(id);}}
}

看完了吗? 可以说所有@Override方法都是被Persenter操控的它压根只负责处理数据,也不会控制view,更不会反过来控制Persenter
mvp实际上看完这个google demo感觉也还是很简单的,给我的感觉就是全接口了,应该是很累的,像我这种小公司追求编码速度效率的话,那些不重用的东西我还是用mvc写,甚至再掺杂一些mvvm的东西进行绑定.
我现在还没咨询过完mvp的大佬,我是感觉没来几个共用我不会这么搞, 有特性的东西,如刷新几乎每一个页面都需要,这个时候一个base 做一套mvp 控制刷新就ok了。

个人愚见,更多参考官方demo,官方demo很多 有你好看

这篇关于学习googlesample demo之安卓架构mvp的正确姿势以及个人分析源码心得的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!


原文地址:
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.chinasem.cn/article/959169

相关文章

MySQL中的LENGTH()函数用法详解与实例分析

《MySQL中的LENGTH()函数用法详解与实例分析》MySQLLENGTH()函数用于计算字符串的字节长度,区别于CHAR_LENGTH()的字符长度,适用于多字节字符集(如UTF-8)的数据验证... 目录1. LENGTH()函数的基本语法2. LENGTH()函数的返回值2.1 示例1:计算字符串

Android kotlin中 Channel 和 Flow 的区别和选择使用场景分析

《Androidkotlin中Channel和Flow的区别和选择使用场景分析》Kotlin协程中,Flow是冷数据流,按需触发,适合响应式数据处理;Channel是热数据流,持续发送,支持... 目录一、基本概念界定FlowChannel二、核心特性对比数据生产触发条件生产与消费的关系背压处理机制生命周期

Knife4j+Axios+Redis前后端分离架构下的 API 管理与会话方案(最新推荐)

《Knife4j+Axios+Redis前后端分离架构下的API管理与会话方案(最新推荐)》本文主要介绍了Swagger与Knife4j的配置要点、前后端对接方法以及分布式Session实现原理,... 目录一、Swagger 与 Knife4j 的深度理解及配置要点Knife4j 配置关键要点1.Spri

怎样通过分析GC日志来定位Java进程的内存问题

《怎样通过分析GC日志来定位Java进程的内存问题》:本文主要介绍怎样通过分析GC日志来定位Java进程的内存问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、GC 日志基础配置1. 启用详细 GC 日志2. 不同收集器的日志格式二、关键指标与分析维度1.

mysql中的服务器架构详解

《mysql中的服务器架构详解》:本文主要介绍mysql中的服务器架构,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1、背景2、mysql服务器架构解释3、总结1、背景简单理解一下mysqphpl的服务器架构。2、mysjsql服务器架构解释mysql的架

MySQL中的表连接原理分析

《MySQL中的表连接原理分析》:本文主要介绍MySQL中的表连接原理分析,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1、背景2、环境3、表连接原理【1】驱动表和被驱动表【2】内连接【3】外连接【4编程】嵌套循环连接【5】join buffer4、总结1、背景

Springboot如何正确使用AOP问题

《Springboot如何正确使用AOP问题》:本文主要介绍Springboot如何正确使用AOP问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录​一、AOP概念二、切点表达式​execution表达式案例三、AOP通知四、springboot中使用AOP导出

python中Hash使用场景分析

《python中Hash使用场景分析》Python的hash()函数用于获取对象哈希值,常用于字典和集合,不可变类型可哈希,可变类型不可,常见算法包括除法、乘法、平方取中和随机数哈希,各有优缺点,需根... 目录python中的 Hash除法哈希算法乘法哈希算法平方取中法随机数哈希算法小结在Python中,

Java Stream的distinct去重原理分析

《JavaStream的distinct去重原理分析》Javastream中的distinct方法用于去除流中的重复元素,它返回一个包含过滤后唯一元素的新流,该方法会根据元素的hashcode和eq... 目录一、distinct 的基础用法与核心特性二、distinct 的底层实现原理1. 顺序流中的去重

k8s上运行的mysql、mariadb数据库的备份记录(支持x86和arm两种架构)

《k8s上运行的mysql、mariadb数据库的备份记录(支持x86和arm两种架构)》本文记录在K8s上运行的MySQL/MariaDB备份方案,通过工具容器执行mysqldump,结合定时任务实... 目录前言一、获取需要备份的数据库的信息二、备份步骤1.准备工作(X86)1.准备工作(arm)2.手