写点什么

GitHub 标星 9K 的 Google 官方 MVP+Rxjava 项目详解,靠这份资料我从 6K 变成了 40K

用户头像
Android架构
关注
发布于: 15 小时前

private TextView mTitle;


private TextView mDescription;


public static AddEditTaskFragment newInstance() {return new AddEditTaskFragment();}


@Overridepublic void onResume() {super.onResume();mPresenter.subscribe();}


@Overridepublic void onPause() {super.onPause();mPresenter.unsubscribe();}


@Overridepublic void setPresenter(@NonNull AddEditTaskContract.Presenter presenter) {mPresenter = checkNotNull(presenter);}


@Overridepublic void onActivityCreated(Bundle savedInstanceState) {super.onActivityCreated(savedInstanceState);


FloatingActionButton fab =(FloatingActionButton) getActivity().findViewById(R.id.fab_edit_task_done);fab.setImageResource(R.drawable.ic_done);fab.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {mPresenter.saveTask(mTitle.getText().toString(),mDescription.getText().toString());}});}


@Nullable@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {View root = inflater.inflate(R.layout.addtask_frag, container, false);mTitle = (TextView) root.findViewById(R.id.add_task_title);mDescription = (TextView) root.findViewById(R.id.add_task_description);


setHasOptionsMenu(true);setRetainInstance(true);return root;}


@Overridepublic void showEmptyTaskError() {Snackbar.make(mTitle, getString(R.string.empty_task_message), Snackbar.LENGTH_LONG).show();}


@Overridepublic void showTasksList() {getActivity().setResult(Activity.RESULT_OK);getActivity().finish();}


@Overridepublic void setTitle(String title) {mTitle.setText(title);}


@Overridepublic void setDescription(String description) {mDescription.setText(description);}


@Overridepublic boolean isActive() {return isAdded();}}


这里的关注重点除了上面提到的订阅和取消订阅方法。还应当有 presenter 实例的获取。通过 setPresenter 方法。


4.3.6AddEditTaskPresenter

在 presenter 的实现类中,可以对 Model 数据进行操作。实例中,数据的获取、存储、数据状态变化都是 model 层的任务,presenter 会根据需要调用该层的数据处理逻辑并在需要时将回调传入。这样 model、presenter、view 都只处理各自的任务,此种实现确实是单一职责最好的诠释。


/**


  • AddEditTaskPresenter 监听用户的 UI 操作,获取数据,更新界面

  • 需要实现的方法有除了{@link BasePresenter} 中的{@link #subscribe()},{@link #unsubscribe()}

  • 还有{@link AddEditTaskContract}中的{@link #saveTask(String, String)} ()},{@link #populateTask()},*/public class AddEditTaskPresenter implements AddEditTaskContract.Presenter {


@NonNullprivate final TasksDataSource mTasksRepository;//数据 model 来源


@NonNullprivate final AddEditTaskContract.View mAddTaskView;//MVP 中的 view


@NonNullprivate final BaseSchedulerProvider mSchedulerProvider;//提供 Scheduler 用于 Rxjava 线程调度


@Nullableprivate String mTaskId;//task 的 id


@NonNullprivate CompositeSubscription mSubscriptions;//CompositeSubscription 持有所有的 Subscriptions


/**


  • 创建添加和编辑 task 的对应 presenter

  • @param taskId 需要编辑的 task 的 id,如果为新建 task 为空

  • @param tasksRepository 是所有 task 数据的入口

  • @param addTaskView 添加/编辑 界面*/public AddEditTaskPresenter(@Nullable String taskId,@NonNull TasksDataSource tasksRepository,@NonNull AddEditTaskContract.View addTaskView,@NonNull BaseSchedulerProvider schedulerProvider) {mTaskId = taskId;mTasksRepository = checkNotNull(tasksRepository, "tasksRepository cannot be null!");mAddTaskView = checkNotNull(addTaskView, "addTaskView cannot be null!");mSchedulerProvider = checkNotNull(schedulerProvider, "schedulerProvider cannot be null!");


mSubscriptions = new CompositeSubscription();mAddTaskView.setPresenter(this);}


@Overridepublic void subscribe() {if (mTaskId != null) {populateTask();}}


@Overridepublic void unsubscribe() {mSubscriptions.clear();}


@Overridepublic void saveTask(String title, String description) {Task newTask = mTaskId == null ?new Task(title, description) :new Task(title, description, mTaskId);saveTask(newTask);}


/**


  • 直接通过 TasksRepository 保存 task

  • @param task*/private void saveTask(@NonNull Task task) {if (task.isEmpty()) {mAddTaskView.showEmptyTaskError();} else {mTasksRepository.saveTask(task);mAddTaskView.showTasksList();}}


/**


  • 根据 id 获取 task*/@Overridepublic void populateTask() {if (mTaskId == null) {throw new RuntimeException("populateTask() was called but task is new.");}Subscription subscription = mTasksRepository.getTask(mTaskId) //获取 task.subscribeOn(mSchedulerProvider.computation()).observeOn(mSchedulerProvider.ui()).subscribe(new Observer<Task>() {@Overridepublic void onCompleted() {


}


@Overridepublic void onError(Throwable e) {if (mAddTaskView.isActive()) {mAddTaskView.showEmptyTaskError(); //调用页面出错}}


@Overridepublic void onNext(Task task) {if (mAddTaskView.isActive()) {mAddTaskView.setTitle(task.getTitle()); //页面正确显示 taskmAddTaskView.setDescription(task.getDescription());}}});


mSubscriptions.add(subscription);}}


这里我在上面的代码中添加了备注,希望尽可能的讲解清楚。这里的代码逻辑是非常的清楚地,下面再捋一捋:


1 AddEditTaskPresenter的构造函数异常重要,这里获取了AddEditTaskContract.view的实例对象和TaskDataSource的实例对象,分别对应了 MVP 中得到 View 和 Model。


2subscribe方法和unSubscribe方法分别对应了订阅和取消订阅状态,这在前面的AddEditTaskFragmentonResumeonPause方法中进行了实现。这里分别完成了获取 task 和取消订阅两个功能。


3 在这里调用了上面提到的setPresenter方法,view 持有 presenter 实例的操作。


4 通过mSubscriptions.add(subscription);将这里获取 task 的subscription添加到了CompositeSubscription中。


5 通过mTasksRepository.saveTask(task);mTasksRepository.getTask(mTaskId)完成了 task 的存储和获取功能,所有 model 层的操作都交给了TasksRepository,model 层的操作将下面详细讲解。


6 我们在onErroronNext中分别完成了错误和正确页面的逻辑处理。

4.4 model 层设计代码分析

Rxjava 完成了数据层和 presenter 层的交互,这里回到上面的代码,可以看到通过 model 层的操作都交给了TasksRepository对象。



接下来到 data 包中就是所有 model 层的操作。



这里就不在展示分析所有代码。TasksLocalDataSource 代表本地数据,TasksRemoteDataSource 代表远程数据。Task 为实体类对象,TasksRepository 为整个数据的核心漱口。这里直接展示 TasksRepository 中的 getTask 方法。


/**


  • Gets tasks from local data source (sqlite) unless the table is new or empty. In that case it

  • uses the network data source. This is done to simplify the sample.*/@Overridepublic Observable<Task> getTask(@NonNull final String taskId) {checkNotNull(taskId);


final Task cachedTask = getTaskWithId(taskId);


// Respond immediately with cache if availableif (cachedTask != null) {return Observable.just(cachedTask);}


// Load from server/persisted if needed.


// Do in memory cache update to keep the app UI up to dateif (mCachedTasks == null) {mCachedTasks = new LinkedHashMap<>();}


// Is the task in the local data source? If not, query the network.Observable<Task> localTask = getTaskWithIdFromLocalRepository(taskId);Observable<Task> remoteTask = mTasksRemoteDataSource.getTask(taskId).doOnNext(new Action1<Task>() {@Overridepublic void call(Task task) {mTasksLocalDataSource.saveTask(task);mCachedTasks.put(task.getId(), task);}});


return


《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》
浏览器打开:qq.cn.hn/FTe 免费领取
复制代码


Observable.concat(localTask, remoteTask).first().map(new Func1<Task, Task>() {@Overridepublic Task call(Task task) {if (task == null) {throw new NoSuchElementException("No task found with taskId " + taskId);}return task;}});}


1 需要注意的是这里 TasksLocalDataSource 使用 SqlBrite 查询数据库并且返回流式数据。


2 关于 model 层 Respository 的了解,可以看我之前的这篇文章。浅析MVP中model层设计3 SqlBrite 是对 Android 系统的 SQLiteOpenHelper 的封装,对 SQL 操作引入了响应式语义 (Rx)(用来在 RxJava 中使用)。详情可以点击[Rxjava+数据库?来用用 SqlBrite 和 SqlDelight 吧!](


) 。

用户头像

Android架构

关注

还未添加个人签名 2021.10.31 加入

还未添加个人简介

评论

发布
暂无评论
GitHub标星9K的Google官方MVP+Rxjava项目详解,靠这份资料我从6K变成了40K