学习googlesampledemo之安卓架构mvp的正确姿势以及个人分析源码心得
简书链接:学习googlesampledemo之安卓架构mvp的正确姿势以及个人分析源码心得
文章字数:1630,阅读全文大约需要6分钟
谈到mvp,我先说说我以前是如何封装刷新 翻页等等的吧.
另外我在没研究mvp之前写的刷新可控制是否加载更多是查询是否是更多 以及需要创建的适配器等等虽然不是接口,但是感觉也实现了一个刷新逻辑的共用
创建一个p,然后把操作接口传递进去传递进去 ,再activity的onCreate() new
出这个p 然后activity实现接口方法 接口方法也包含了模型的查询,数据的查询也是在p层操作,但是具体请求地址是啥,地址成功之后的数据类型结果的返回还是通过申明的接口,
直接附上代码吧,各位说说这都叫什么模式,这都是我想出来的共用。
mvp把是完全的接口了,我这mvp又不像mvc也不像,传说中的4不像?但是我的确解决了不同类型无法改变的结类的 如activity fragment 共用一个逻辑,只需要复写这些重新定义即可,但是内部的核心还是那些。
1 |
|
我突然觉得,我这里应该直接 把activity 的BaseJSONRefreshLogicI
传递过去,而不是通过复写匿名类的方法接控制外部类,不过坏处就是所有逻辑都要复写,我这里只是针对性的复写一些。
另外,我这叫啥子写法,是一套解决点赞 等+1 -1的封装
1 | public interface IOperaAction { |
1 | public static void addAction(Activity activity, final String function, String addUrl, String deleteUrl, final IOperaAction action) { |
好了,不说这个了
开始正文
打开项目是不是就只会一个一个zip包下载?多累啊,
其实仔细点开链接发现地址前缀是同一个,于是焕然大悟,难怪谷歌也说推荐git clone
呢
首先要学习git
的朋友看看我写的这篇文章
http://qssq666.cn/2016/08/26/%E5%AD%A6%E4%B9%A0git%E5%BF%83%E5%BE%97/
1 | git clone https://github.com/googlesamples/android-architecture.git qssq-lean-android-architecture |
刚进去只能看到几个文档md的,需要切换分支。
查看该项目所有分支
1 | git branch -a |
切换分支演示
1 | ```git branch```查看当前所处哪个分支,会发现当前分支颜色是不相同的 其实我是从master->todo-mvp->todo-mvp-rxjava的,上面的图已经暴露我的操作行踪了,尴尬不 |
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
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();
}
});
}
}
1 |
|
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();
}
}
1 |
|
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<Task> 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<Map.Entry<String, Task>> it = mCachedTasks.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<String, Task> 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<Task> tasks) {
refreshCache(tasks);
refreshLocalDataSource(tasks);
callback.onTasksLoaded(new ArrayList<>(mCachedTasks.values()));
}
@Override
public 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);
}
}
@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很多 有你好看