Google官方Android App架构蓝图

作者: 不二先生的世界 | 来源:发表于2016-04-02 20:20 被阅读2488次
    Android Developer.png

    众所周知,Android Framework提供了大量灵活的方式来定义如何组织和架构一个Android App,自由,附有价值,但同时也导致App拥有了大量的类,不一致的命名和架构也给测试,维护和拓展带来了困难。由此带来了很多的App架构,MVC、MVP,MVVM等,前几天Google官方推出了关于Android 架构蓝图的Sample,借此来引导Android开发者解决这些问题,创建自己的App。重点放在代码结构,测试和维护。目前推出了3个Sample,接下来还会继续推出,至于在项目中用哪个取决于你自己。这些Sample不能算是经典例子,但可以作为参考。不过从刚推出就在Github趋势上位列前茅,也能感受到大家对此的期待。

    Demo运行图

    Demo运行图.png

    TODO-MVP

    架构图

    TODO-MVP架构图.png

    架构解析

    代码结构.png

    这个是很经典的MVP架构,从代码结构上也能看到一些启发,按业务功能进行划分,例如addedittask(新增任务),taskdetail(任务详情)等,里面含有相关的Presenter,View,Activity和Fragment,这样做的好处是可以方便的找到业务功能代码。
    我们以addedittask为例:
    AddEditTaskActivity:因为用了Fragment来显示页面,Activity没有过多的逻辑。
    AddEditTaskContract:里面包含View和Presenter接口类

    public interface AddEditTaskContract {
    
        interface View extends BaseView<Presenter> {
    
            void showEmptyTaskError();
    
            void showTasksList();
    
            void setTitle(String title);
    
            void setDescription(String description);
    
            boolean isActive();
        }
    
        interface Presenter extends BasePresenter {
    
            void createTask(String title, String description);
    
            void updateTask( String title, String description);
    
            void populateTask();
        }
    }
    

    AddEditTaskFragment:

    public class AddEditTaskFragment extends Fragment implements AddEditTaskContract.View {
        ......//省略
    
        public static AddEditTaskFragment newInstance() {
            return new AddEditTaskFragment();
        }
    
        public AddEditTaskFragment() {
            // Required empty public constructor
        }
    
        @Override
        public void onResume() {
            super.onResume();
            mPresenter.start();
        }
    
        @Override
        public void setPresenter(@NonNull AddEditTaskContract.Presenter presenter) {
            mPresenter = checkNotNull(presenter);
        }
    
        @Override
        public 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() {
                @Override
                public void onClick(View v) {
                    if (isNewTask()) {
                        mPresenter.createTask(
                                mTitle.getText().toString(),
                                mDescription.getText().toString());
                    } else {
                        mPresenter.updateTask(
                                mTitle.getText().toString(),
                                mDescription.getText().toString());
                    }
    
                }
            });
        }
    
        @Nullable
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
                                 Bundle savedInstanceState) {
            View root = inflater.inflate(R.layout.addtask_frag, container, false);
            ......//省略
            return root;
        }
    
        @Override
        public void showEmptyTaskError() {
            Snackbar.make(mTitle, getString(R.string.empty_task_message), Snackbar.LENGTH_LONG).show();
        }
    
        @Override
        public void showTasksList() {
            getActivity().setResult(Activity.RESULT_OK);
            getActivity().finish();
        }
    
        @Override
        public void setTitle(String title) {
            mTitle.setText(title);
        }
    
        @Override
        public void setDescription(String description) {
            mDescription.setText(description);
        }
    
        @Override
        public boolean isActive() {
            return isAdded();
        }
    
        private boolean isNewTask() {
            return mEditedTaskId == null;
        }
    }
    

    AddEditTaskPresenter:Presenter实现类,业务逻辑的实现

    public class AddEditTaskPresenter implements AddEditTaskContract.Presenter,
            TasksDataSource.GetTaskCallback {
           ......//省略
    
        /**
         * Creates a presenter for the add/edit view.
         *
         * @param taskId ID of the task to edit or null for a new task
         * @param tasksRepository a repository of data for tasks
         * @param addTaskView the add/edit view
         */
        public AddEditTaskPresenter(@Nullable String taskId, @NonNull TasksDataSource tasksRepository,
                @NonNull AddEditTaskContract.View addTaskView) {
            mTaskId = taskId;
            mTasksRepository = checkNotNull(tasksRepository);
            mAddTaskView = checkNotNull(addTaskView);
    
            mAddTaskView.setPresenter(this);
        }
    
        @Override
        public void start() {
            if (mTaskId != null) {
                populateTask();
            }
        }
    
        @Override
        public void createTask(String title, String description) {
            Task newTask = new Task(title, description);
            if (newTask.isEmpty()) {
                mAddTaskView.showEmptyTaskError();
            } else {
                mTasksRepository.saveTask(newTask);
                mAddTaskView.showTasksList();
            }
        }
    
        @Override
        public void updateTask(String title, String description) {
            if (mTaskId == null) {
                throw new RuntimeException("updateTask() was called but task is new.");
            }
            mTasksRepository.saveTask(new Task(title, description, mTaskId));
            mAddTaskView.showTasksList(); // After an edit, go back to the list.
        }
    
        @Override
        public void populateTask() {
            if (mTaskId == null) {
                throw new RuntimeException("populateTask() was called but task is new.");
            }
            mTasksRepository.getTask(mTaskId, this);
        }
    
        @Override
        public void onTaskLoaded(Task task) {
            // The view may not be able to handle UI updates anymore
            if (mAddTaskView.isActive()) {
                mAddTaskView.setTitle(task.getTitle());
                mAddTaskView.setDescription(task.getDescription());
            }
        }
    
        @Override
        public void onDataNotAvailable() {
            // The view may not be able to handle UI updates anymore
            if (mAddTaskView.isActive()) {
                mAddTaskView.showEmptyTaskError();
            }
        }
    }
    

    TODO-MVP-Loaders

    架构图

    TODO-MVP-Loaders架构图.png

    架构分析

    和TODO-MVP的区别是通过Loader对数据进行异步加载,监控其数据源并在内容变化时传递新结果。关于Loader的使用,可以直接看官方文档,我就不复述了。

    TODO-DataBinding

    架构图

    TODO-DataBinding架构图.png

    架构分析

    和TODO-MVP的区别是通过Data Binding来绑定app逻辑和layouts文件。关于Data Binding的使用,可以直接看官方文档,我就不复述了。

    总结

    通过MVP进行业务逻辑和视图的分离,让View专注于处理数据的可视化以及与用户的交互,同时让Repository只关系数据的处理,让Presenter作为View和Repository之间的纽带,易于维护和测试。代码比较简单,具体是否使用Loader和Data Binding就看个人喜好了。虽然Google并没有把这些当做指导文档,但也算给Android开发者带来了一些思路。

    参考资料

    Android-Architecture
    Github
    Loader文档
    Data Binding文档

    欢迎关注我的微博

    相关文章

      网友评论

      • loszer:楼主你的这个工程可以build通过么,我的一直出错,lint检测出了不安全的类型转换
        不二先生的世界:@loszer 我是可以的,不安全的类型转换是没有关系的,你应该是gradle加载问题吧。
      • 程序亦非猿:棒棒的
        不二先生的世界: @程序亦非猿 谢谢

      本文标题:Google官方Android App架构蓝图

      本文链接:https://www.haomeiwen.com/subject/wcnylttx.html