关闭

android google mvp

标签: android谷歌mvp
437人阅读 评论(1) 收藏 举报
分类:

google官方mvp demo的地址:
https://github.com/googlesamples/android-architecture/tree/todo-mvp/

下面对这个demo进行分析
先看一下\app\src\main\java目录结构

目录结构

每一个页面都有一个文件夹,其中包括4个主要的类
Activity 管理Fragment, 建立Fragment和对应的Presenter之间的关系
Constract 定义View和Presenter接口
Fragment 只负责显示View。要进行什么操作,就调用Presenter中的对应的方法。
Presenter 处理各种逻辑,然后调用Framgnet中的操作View的方法,进行相应的显示。

下面对任务详情模块,也就是taskdetail文件夹进行分析
首先是STaskDetailActivity关键代码

public class TaskDetailActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {

        //添加TaskDetailFragment
        TaskDetailFragment taskDetailFragment = (TaskDetailFragment) getSupportFragmentManager()
                .findFragmentById(R.id.contentFrame);
        if (taskDetailFragment == null) {
            taskDetailFragment = TaskDetailFragment.newInstance(taskId);
            ActivityUtils.addFragmentToActivity(getSupportFragmentManager(),
                    taskDetailFragment, R.id.contentFrame);
        }

        // new TaskDetailPresenter对象,传入一个值,tasksRepository,和taskDetailFragment
        new TaskDetailPresenter(taskId,Injection.provideTasksRepository(getApplicationContext()),taskDetailFragment);
    }
}

TaskDetailPresenter类

public interface TaskDetailContract {
    //定义View接口,也就是要对View进行的操作,需要的数据会在参数中传入
    interface View extends BaseView<Presenter> {
        void setLoadingIndicator(boolean active);
        void showMissingTask();
        void hideTitle();
        void showTitle(String title);
        void hideDescription();
        void showDescription(String description);
        void showCompletionStatus(boolean complete);
        void showEditTask(String taskId);
        void showTaskDeleted();
        void showTaskMarkedComplete();
        void showTaskMarkedActive();
        boolean isActive();
    }

    //定义Presenter接口,就是要进行的操作
    interface Presenter extends BasePresenter {
        void editTask();
        void deleteTask();
        void completeTask();
        void activateTask();
    }
}

TaskDetailPresenter类关键代码

public class TaskDetailPresenter implements TaskDetailContract.Presenter {

    public TaskDetailPresenter(@Nullable String taskId, @NonNull TasksRepository tasksRepository, @NonNull TaskDetailContract.View taskDetailView) {
        this.mTaskId = taskId;
        //拿到TasksRepository
        mTasksRepository = checkNotNull(tasksRepository, "tasksRepository cannot be null!");

        //拿到TaskDetailFragment继承的View接口,这样就可以操作fragment中的View了
        mTaskDetailView = checkNotNull(taskDetailView, "taskDetailView cannot be null!");

        //将这个TaskDetailPresenter实例,传入到View接口中,也就是传到fragment中
        mTaskDetailView.setPresenter(this);
    }

    //BasePresent中的类,开始调用Presenter的方法
    @Override
    public void start() {
        openTask();
    }

    private void openTask() {
        //根据mTaskId,调用fragment中操作view的方法
        if (null == mTaskId || mTaskId.isEmpty()) {
            mTaskDetailView.showMissingTask();
            return;
        }

        //调用fragment中操作view的方法
        mTaskDetailView.setLoadingIndicator(true);
        //通过mTasksRepository获取数据,根据结果调用fragment中操作view的方法
        mTasksRepository.getTask(mTaskId, new TasksDataSource.GetTaskCallback() {
            @Override
            public void onTaskLoaded(Task task) {
                if (!mTaskDetailView.isActive()) {
                    return;
                }
                mTaskDetailView.setLoadingIndicator(false);
                if (null == task) {
                    mTaskDetailView.showMissingTask();
                } else {
                    showTask(task);
                }
            }
            @Override
            public void onDataNotAvailable() {
                if (!mTaskDetailView.isActive()) {
                    return;
                }
                mTaskDetailView.showMissingTask();
            }
        });
    }
}

TaskDetailFragment类中关键代码

public class TaskDetailFragment extends Fragment implements TaskDetailContract.View {

    //这里的mPresenter,在Activity中new TaskDetailPresenter的时,已经被初始化了
    //也就是TaskDetailPresente的构造函数中调用mTaskDetailView.setPresenter(this)方法时
    //也就是本类中的setPresenter方法
    private TaskDetailContract.Presenter mPresenter;

    @Override
    public void onResume() {
        super.onResume();
        //页面打开时,调用mPresenter.start()方法
        mPresenter.start();
    }

    //初始化当前的mPresenter
    @Override
    public void setPresenter(@NonNull TaskDetailContract.Presenter presenter) {
        mPresenter = checkNotNull(presenter);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case R.id.menu_delete:
                //调用mPresenter中的方法
                mPresenter.deleteTask();
                return true;
        }
        return false;
    }

    //操作view
    @Override
    public void hideTitle() {
        mDetailTitle.setVisibility(View.GONE);
    }

    //操作view
    @Override
    public void showTitle(String title) {
        mDetailTitle.setVisibility(View.VISIBLE);
        mDetailTitle.setText(title);
    }
    //操作view
    @Override
    public void showMissingTask() {
        mDetailTitle.setText("");
        mDetailDescription.setText(getString(R.string.no_data));
    }
}

上面介绍mvp中的View和Presenter,关于moudle,他是用来操作数据的,由Presenter调用,封装起来,好用就行。下面看一下这个demo中moudle是怎么封装的

在TaskDetailActivity中,调用了Injection类,这个类的作用就是获得一个模块的仓库实例

public class Injection {
    //获得TasksRepository实例,同时在TasksRepository初始化远程数据源(接口)和本地存储数据源
    public static TasksRepository provideTasksRepository(@NonNull Context context) {
        checkNotNull(context);
        return TasksRepository.getInstance(FakeTasksRemoteDataSource.getInstance(), TasksLocalDataSource.getInstance(context));
    }
}

那么Prensent要怎么获取数据呢?比如在TaskDetailPresenter类中

       mTasksRepository.getTask(mTaskId, new TasksDataSource.GetTaskCallback() {
            @Override
            public void onTaskLoaded(Task task) { 

            }
            @Override
            public void onDataNotAvailable() { 

            }
        });

再看TasksRepository类中的getTask方法

 public void getTask(@NonNull final String taskId, @NonNull final GetTaskCallback callback) {
        checkNotNull(taskId);
        checkNotNull(callback);

        if (cachedTask != null) {
            callback.onTaskLoaded(cachedTask);   
            return;
        }

        //先获取本地数据
        mTasksLocalDataSource.getTask(taskId, new GetTaskCallback() {
            @Override
            public void onTaskLoaded(Task task) {
                callback.onTaskLoaded(task);    
            }

            @Override
            public void onDataNotAvailable() {
                mTasksRemoteDataSource.getTask(taskId, new GetTaskCallback() {
                    //本地数据获取不到,获取远程数据,也就是访问接口
                    @Override
                    public void onTaskLoaded(Task task) {
                        callback.onTaskLoaded(task);    
                    }

                    @Override
                    public void onDataNotAvailable() {
                        callback.onDataNotAvailable();    
                    }
                });
            }
        });
    }

其中mTasksLocalDataSource,mTasksRemoteDataSource都是TasksDataSource接口定义的,在Activity中调用Injection方法初始化的。下面分别看一下TasksDataSource接口的实现类TasksRemoteDataSource和TasksLocalDataSource。

public class TasksRemoteDataSource implements TasksDataSource {
    @Override
    public void getTask(@NonNull String taskId, final @NonNull GetTaskCallback callback) {
        final Task task = TASKS_SERVICE_DATA.get(taskId);
        Handler handler = new Handler();
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                callback.onTaskLoaded(task);
            }
        }, SERVICE_LATENCY_IN_MILLIS);
    }
}
public class TasksLocalDataSource implements TasksDataSource {
    @Override
    public void getTask(@NonNull String taskId, @NonNull GetTaskCallback callback) {
        SQLiteDatabase db = mDbHelper.getReadableDatabase();
        String[] projection = {
                TaskEntry.COLUMN_NAME_ENTRY_ID,
                TaskEntry.COLUMN_NAME_TITLE,
                TaskEntry.COLUMN_NAME_DESCRIPTION,
                TaskEntry.COLUMN_NAME_COMPLETED
        };
        String selection = TaskEntry.COLUMN_NAME_ENTRY_ID + " LIKE ?";
        String[] selectionArgs = { taskId };
        Cursor c = db.query(
                TaskEntry.TABLE_NAME, projection, selection, selectionArgs, null, null, null);
        Task task = null;
        if (c != null && c.getCount() > 0) {
            c.moveToFirst();
            String itemId = c.getString(c.getColumnIndexOrThrow(TaskEntry.COLUMN_NAME_ENTRY_ID));
            String title = c.getString(c.getColumnIndexOrThrow(TaskEntry.COLUMN_NAME_TITLE));
            String description = c.getString(c.getColumnIndexOrThrow(TaskEntry.COLUMN_NAME_DESCRIPTION));
            boolean completed = c.getInt(c.getColumnIndexOrThrow(TaskEntry.COLUMN_NAME_COMPLETED)) == 1;
            task = new Task(title, description, itemId, completed);
        }
        if (c != null) {
            c.close();
        }
        db.close();
        if (task != null) {
            callback.onTaskLoaded(task);
        } else {
            callback.onDataNotAvailable();
        }
    }
}

好啦,代码终于看完了!
我觉得mvp最大的好处是,适合于多人开发一个项目。这样对项目的结果也有了一套明确的规范,增加了代码的可读性和可维护性。并且Activity,Fragment只负责显示View就好,有什么操作都交给了Presenter,Presenter的代码量其实也没有那么多,数据处理都是moudle层做的,他负责回调得到数据就好了。moudle层什么都不用关心,就是处理数据。 这样每个模块的的代码都很少,很简洁,特别是Activity,Fragment看起来无比的清爽,瞬间开心的感觉有木有。

1
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:14147次
    • 积分:629
    • 等级:
    • 排名:千里之外
    • 原创:51篇
    • 转载:0篇
    • 译文:0篇
    • 评论:4条