谈到mvp,我先说说我以前是如何封装刷新 翻页等等的吧.
另外我在没研究mvp之前写的刷新可控制是否加载更多是查询是否是更多 以及需要创建的适配器等等虽然不是接口,但是感觉也实现了一个刷新逻辑的共用
创建一个p,然后把操作接口传递进去传递进去 ,再activity的onCreate() new
出这个p 然后activity实现接口方法 接口方法也包含了模型的查询,数据的查询也是在p层操作,但是具体请求地址是啥,地址成功之后的数据类型结果的返回还是通过申明的接口,
直接附上代码吧,各位说说这都叫什么模式,这都是我想出来的共用。
mvp把是完全的接口了,我这mvp又不像mvc也不像,传说中的4不像?但是我的确解决了不同类型无法改变的结类的 如activity fragment 共用一个逻辑,只需要复写这些重新定义即可,但是内部的核心还是那些。
public abstract class BaseJSONRefreshActivityN extends BaseActionBarActivity implements BaseJSONRefreshLogicI {
public JSONRefreshRefreshWrap getRefreshWrap() {
return refreshWrap;
}
private JSONRefreshRefreshWrap refreshWrap;
@Override
protected final void init(Bundle savedInstanceState) {
refreshWrap = new JSONRefreshRefreshWrap() {
@Override
protected List parseJsonResult(String json) {
return BaseJSONRefreshActivityN.this.parseJsonResult(json);
}
@Override
public RecyclerView getRecyclerView() {
return BaseJSONRefreshActivityN.this.getRecyclerView();
}
public String getInterceptEmptyDataTip(){
return BaseJSONRefreshActivityN.this.getInterceptEmptyDataTip();
}
public boolean isInterceptEmptyData(){
return BaseJSONRefreshActivityN.this.isInterceptEmptyData();
}
@Override
public void onParseSucc(List list) {
BaseJSONRefreshActivityN.this.onParseSucc(list);
}
@Override
public SmartRefreshLayout getSwipyRefreshLayout() {
return (SmartRefreshLayout) BaseJSONRefreshActivityN.this.getSwipyRefreshLayout();
}
@Override
public void onInitStart() {
BaseJSONRefreshActivityN.this.onInitStart();
}
@Override
public void onInitFinish() {
BaseJSONRefreshActivityN.this.onInitFinish();
}
@Override
public RecyclerView.LayoutManager onCreateLayoutManager() {
return BaseJSONRefreshActivityN.this.onCreateLayoutManager();
}
@Override
public ADAPTER onCreateAdapter() {
return BaseJSONRefreshActivityN.this.onCreateAdapter();
}
@Override
public String getUrl(int page) {
return BaseJSONRefreshActivityN.this.getUrl(page);
}
@Override
public boolean autoLoad() {
return BaseJSONRefreshActivityN.this.autoLoad();
}
@Override
public boolean enableLoadMore() {
return BaseJSONRefreshActivityN.this.enableLoadMore();
}
@Override
protected 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() {
@Override
public 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 + "失败");
}
}
@Override
public void onFail(String str) {
ToastUtils.showToast(cannel + function + "失败 服务器错误 " + str);
}
});
}
//实际上服务器有时候不弄累加值得,这里贴的没有自动给+1 -1的,但是可以解决多个地方不同接口的点赞
好了,不说这个了
开始正文
打开项目是不是就只会一个一个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
切换分支演示
git checkout todo-mvp
当然我这里是切换到另外一个分支,
git branch
查看当前所处哪个分支,会发现当前分支颜色是不相同的 其实我是从master->todo-mvp->todo-mvp-rxjava的,上面的图已经暴露我的操作行踪了,尴尬不
再详细一点点
git branch -l
查看本地分支
git branch -r
查看远程分支
好,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,
先上个图再看代码
从图上可以看出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);
}
@Override
public void start() {
loadStatistics();
}
private void loadStatistics() {
mStatisticsView.setProgressIndicator(true);
EspressoIdlingResource.increment(); // App is busy until further notice
mTasksRepository.getTasks(new TasksDataSource.LoadTasksCallback() {
@Override
public void onTasksLoaded(List tasks) {
int activeTasks = 0;
int completedTasks = 0;
if (!EspressoIdlingResource.getIdlingResource().isIdleNow()) {
EspressoIdlingResource.decrement(); // Set app as idle.
}
// We calculate number of active and completed tasks
for (Task task : tasks) {
if (task.isCompleted()) {
completedTasks += 1;
} else {
activeTasks += 1;
}
}
// The view may not be able to handle UI updates anymore
if (!mStatisticsView.isActive()) {
return;
}
mStatisticsView.setProgressIndicator(false);
mStatisticsView.showStatistics(activeTasks, completedTasks);
}
@Override
public 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();
}
@Override
public void setPresenter(@NonNull StatisticsContract.Presenter presenter) {
mPresenter = checkNotNull(presenter);
}
@Nullable
@Override
public 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;
}
@Override
public void onResume() {
super.onResume();
mPresenter.start();
}
@Override
public void setProgressIndicator(boolean active) {
if (active) {
mStatisticsTV.setText(getString(R.string.loading));
} else {
mStatisticsTV.setText("");
}
}
@Override
public 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);
}
}
@Override
public void showLoadingStatisticsError() {
mStatisticsTV.setText(getResources().getString(R.string.statistics_error));
}
@Override
public boolean isActive() {
return isAdded();
}
}
从上面代码体现了2个信息
非fragment本身的@Override
实际上是p控制v的过程
而fragment也调用了mPresenter.start()
实际上是反过来控制Persenter
start()
实际上是间接让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;
}
@Override
public void getTasks(@NonNull final LoadTasksCallback callback) {
checkNotNull(callback);
// Respond immediately with cache if available and not dirty
if (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() {
@Override
public void onTasksLoaded(List tasks) {
refreshCache(tasks);
callback.onTasksLoaded(new ArrayList<>(mCachedTasks.values()));
}
@Override
public void onDataNotAvailable() {
getTasksFromRemoteDataSource(callback);
}
});
}
}
@Override
public 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 date
if (mCachedTasks == null) {
mCachedTasks = new LinkedHashMap<>();
}
mCachedTasks.put(task.getId(), task);
}
@Override
public 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 date
if (mCachedTasks == null) {
mCachedTasks = new LinkedHashMap<>();
}
mCachedTasks.put(task.getId(), completedTask);
}
@Override
public void completeTask(@NonNull String taskId) {
checkNotNull(taskId);
completeTask(getTaskWithId(taskId));
}
@Override
public 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 date
if (mCachedTasks == null) {
mCachedTasks = new LinkedHashMap<>();
}
mCachedTasks.put(task.getId(), activeTask);
}
@Override
public void activateTask(@NonNull String taskId) {
checkNotNull(taskId);
activateTask(getTaskWithId(taskId));
}
@Override
public void clearCompletedTasks() {
mTasksRemoteDataSource.clearCompletedTasks();
mTasksLocalDataSource.clearCompletedTasks();
// Do in memory cache update to keep the app UI up to date
if (mCachedTasks == null) {
mCachedTasks = new LinkedHashMap<>();
}
Iterator> it = mCachedTasks.entrySet().iterator();
while (it.hasNext()) {
Map.Entry entry = it.next();
if (entry.getValue().isCompleted()) {
it.remove();
}
}
}
@Override
public 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() {
@Override
public void onTaskLoaded(Task task) {
// Do in memory cache update to keep the app UI up to date
if (mCachedTasks == null) {
mCachedTasks = new LinkedHashMap<>();
}
mCachedTasks.put(task.getId(), task);
callback.onTaskLoaded(task);
}
@Override
public void onDataNotAvailable() {
mTasksRemoteDataSource.getTask(taskId, new GetTaskCallback() {
@Override
public void onTaskLoaded(Task task) {
// Do in memory cache update to keep the app UI up to date
if (mCachedTasks == null) {
mCachedTasks = new LinkedHashMap<>();
}
mCachedTasks.put(task.getId(), task);
callback.onTaskLoaded(task);
}
@Override
public void onDataNotAvailable() {
callback.onDataNotAvailable();
}
});
}
});
}
@Override
public void refreshTasks() {
mCacheIsDirty = true;
}
@Override
public void deleteAllTasks() {
mTasksRemoteDataSource.deleteAllTasks();
mTasksLocalDataSource.deleteAllTasks();
if (mCachedTasks == null) {
mCachedTasks = new LinkedHashMap<>();
}
mCachedTasks.clear();
}
@Override
public 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() {
@Override
public void onTasksLoaded(List tasks) {
refreshCache(tasks);
refreshLocalDataSource(tasks);
callback.onTasksLoaded(new ArrayList<>(mCachedTasks.values()));
}
@Override
public void onDataNotAvailable() {
callback.onDataNotAvailable();
}
});
}
private void refreshCache(List tasks) {
if (mCachedTasks == null) {
mCachedTasks = new LinkedHashMap<>();
}
mCachedTasks.clear();
for (Task task : tasks) {
mCachedTasks.put(task.getId(), task);
}
mCacheIsDirty = false;
}
private void refreshLocalDataSource(List tasks) {
mTasksLocalDataSource.deleteAllTasks();
for (Task task : tasks) {
mTasksLocalDataSource.saveTask(task);
}
}
@Nullable
private 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很多 有你好看