Google Samples 学习之 todo-mvp(一)

之前学习 MVP 模式都是通过定性的分析和描述进行的,不够直观,现在则要通过解析简单的示例项目来深入学习 MVP 架构。 学习 MVP 最好的项目当属 Google 官方在 GitHub 上开源的示例项目: Android Architecture Blueprints 这个项目现在还在不断更新推出新的架构模式示例代码(比如 MVVM 示例),不同的架构方法使用不同的分支来演示,其中最简单、最基础的就是名为 todo-mvp 的架构方法。这个架构方法仅仅使用自定义的接口实现了最简单的 MVP 架构,尽量避免使用复杂的以及与 MVP 架构本身无关的技术,是入门 MVP 学习的最佳范本。

准备工作

学习项目需要了解 MVP 架构的基本知识: Android MVP 架构学习(一) Android MVP 架构学习(二)

根据官方的指导,不能直接使用 Android Studio 载入项目文件夹,需要先使用 Git 切换到相应的分支才行。 具体操作非常简单:

  1. clone 项目到本地:
1
git clone https://github.com/googlesamples/android-architecture.git
  1. 检出分支 todo-mvp:
1
git checkout todo-mvp
  1. 导入项目文件夹到 Android Studio 或 Intellij(注意使用导入 Gradle 项目的功能)

如无意外,导入过程会顺利完成。如果出现错误,一般是 Android Studio 版本或 Android SDK 版本太低,手动更新到最新即可。

项目概览

启动后会进入任务总览页面:

tasks.png

点击任务总览页面右下角的 + 按钮能够添加任务:

add_edit_task.png

如果添加任务后再返回任务总览页面,可以看的相应任务标题以列表项方式显示,点击后进入任务内容页面:

task_detail.png

还是在任务总览页面,滑动或点击左上方菜单按钮可以呼出滑动菜单:

slide_menu.png

在滑动菜单中选择 statistics 项目可以进入任务统计页面:

statistics.png

另外,在每个页面上方还有不同的工具栏菜单项可选择,这里只列出任务总览页面的菜单,其他的在分析相应功能时再讨论:

toolbar1.png
toolbar2.png

这些就是 app 运行时会绘制的注意页面,其他功能导致的 UI 元素变化也是在这些页面中发生的,具体分析的时候再做说明。

dependencies 部分的代码如下所示:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
/*
 Dependency versions are defined in the top level build.gradle file. This helps keeping track of
 all versions in a single place. This improves readability and helps managing project complexity.
 */
dependencies {
    // App's dependencies, including test
    compile "com.android.support:appcompat-v7:$rootProject.supportLibraryVersion"
    compile "com.android.support:cardview-v7:$rootProject.supportLibraryVersion"
    compile "com.android.support:design:$rootProject.supportLibraryVersion"
    compile "com.android.support:recyclerview-v7:$rootProject.supportLibraryVersion"
    compile "com.android.support:support-v4:$rootProject.supportLibraryVersion"
    compile "com.android.support.test.espresso:espresso-idling-resource:$rootProject.espressoVersion"
    compile "com.google.guava:guava:$rootProject.guavaVersion"

    // Dependencies for local unit tests
    testCompile "junit:junit:$rootProject.ext.junitVersion"
    testCompile "org.mockito:mockito-all:$rootProject.ext.mockitoVersion"
    testCompile "org.hamcrest:hamcrest-all:$rootProject.ext.hamcrestVersion"

    // Android Testing Support Library's runner and rules
    androidTestCompile "com.android.support.test🏃‍♂️$rootProject.ext.runnerVersion"
    androidTestCompile "com.android.support.test:rules:$rootProject.ext.runnerVersion"

    // Dependencies for Android unit tests
    androidTestCompile "junit:junit:$rootProject.ext.junitVersion"
    androidTestCompile "org.mockito:mockito-core:$rootProject.ext.mockitoVersion"
    androidTestCompile 'com.google.dexmaker:dexmaker:1.2'
    androidTestCompile 'com.google.dexmaker:dexmaker-mockito:1.2'

    // Espresso UI Testing
    androidTestCompile "com.android.support.test.espresso:espresso-core:$rootProject.espressoVersion"
    androidTestCompile "com.android.support.test.espresso:espresso-contrib:$rootProject.espressoVersion"
    androidTestCompile "com.android.support.test.espresso:espresso-intents:$rootProject.espressoVersion"

    // Resolve conflicts between main and test APK:
    androidTestCompile "com.android.support:support-annotations:$rootProject.supportLibraryVersion"
    androidTestCompile "com.android.support:support-v4:$rootProject.supportLibraryVersion"
    androidTestCompile "com.android.support:recyclerview-v7:$rootProject.supportLibraryVersion"
    androidTestCompile "com.android.support:appcompat-v7:$rootProject.supportLibraryVersion"
    androidTestCompile "com.android.support:design:$rootProject.supportLibraryVersion"
}

文件已经对不同功能用到的依赖使用空行和注释做了大体的分隔,下面对每个代码块进行分析: 第一块:

  • 使用了 appcompat-v7 和 support-v4 库,这比较常见
  • 使用了 cardview-v7 和 recyclerview-v7 库来实现任务列表显示
  • 使用了 design 库实现 Material Design 风格界面
  • 使用 Espresso 进行 UI 测试
  • 使用了 Guava 库的部分功能(Guava 功能太多了,目前没有深入代码查看暂时无法得知使用了什么)

第二块:

  • 使用 JUnit 进行 Android API 无关的单元测试
  • 使用 Hamcrest 库作为匹配工具,辅助单元测试

第三块:

  • 使用 Android 测试支持库中的 runner 和 rules 库辅助 Android API 相关的测试

第四块:

  • 使用 JUnit 进行 UI 测试
  • 使用 Mockito 库进行 mock 测试
  • 使用 Dexmaker 生成 Dalvik 字节码,辅助 Mockito 库更好地模拟 Android API

第五块:

而这些依赖的版本号因为要重复多次使用,则在项目的 build.gradle 文件中统一定义和管理:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
// Define versions in a single place
ext {
    // Sdk and tools
    minSdkVersion = 10
    targetSdkVersion = 25
    compileSdkVersion = 25
    buildToolsVersion = '25.0.2'

    // App dependencies
    supportLibraryVersion = '25.1.1'
    guavaVersion = '18.0'
    junitVersion = '4.12'
    mockitoVersion = '1.10.19'
    powerMockito = '1.6.2'
    hamcrestVersion = '1.3'
    runnerVersion = '0.5'
    rulesVersion = '0.5'
    espressoVersion = '2.2.2'
}

后续文章

后续会对目录 addedittask、data 中的代码进行分析。statistics 和 taskdetail 目录同 addedittask 目录结构没有太大区别,代码的组织和实现方式也同 addedittask、tasks 相似,因此不重复分析。