Wallet 从零开始-01

713 阅读4分钟

前言

最近了解学习了一些Jetpack/AndroidX上更新的一些【技术】,再加上想对区块链知识更多一些了解,于是就想写一个简单的钱包应用来巩固下。 项目中我们将使用到:

  1. Navigation Component
  2. 自定义plugin + includeBuild 实现依赖库管理
  3. Kotlin/Kotlin flow
  4. Activity Result API 实现权限申请和替换onActivityResult
  5. Koin 依赖注入
  6. MVVM 架构模式
  7. Coroutine + Retrofit + Moshi 实现网络请求
  8. Room 实现本地存储

APP说明

本次写的应用比较简单, 只要涵盖了钱包简单助记词的简单导入,支持Bitcoin,Ethereum,CRO 3种币种,支持设置首页显示支持的币种,转账,接收和查看交易历史记录的功能。我已经在GitHub上提交了一些代码。

GitHub:Wallet

备注:由于我使用的是Android Studio 4.1-beta版本,所以Gradle 版本比较高,可能在4.1之前的版本编译不过。 由于时间问题,项目还不是很完整,部分还是为了验证结果简单实现一下。

自定义plugin + includeBuild

在项目中你可以看到有一个依赖库是 dep-version,其实这个就是一个依赖库版本管理module来的。

  • 加一个类继承 org.gradle.api.Plugin
  • 在build.gradle 加上
gradlePlugin {
    plugins {
        version {
            id = 'com.dougie.version'
            implementationClass = 'com.dougie.version.DependencyVersionPlugin'
        }
    }
}
  • settings.gralde 中使用
includeBuild("dep-version")
  • 此时已经配置完成了,接下来是把你需要依赖的库放到dep-version中去创建一个object kotlin文件,将你需要的依赖库添加上去
object Other {
    const val material = "com.google.android.material:material:1.3.0-alpha01"
    const val flexbox = "com.google.android:flexbox:2.0.1"
    const val coroutineCore = "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.2"
    const val coroutineAndroid = "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.2"
    ...
}
  • 最后在需要的module中使用
// kts
plugins {
    id("com.dougie.version")
}
// not kts
plugins {
    id "com.dougie.version"
}

dependencies {
    api("org.jetbrains.kotlin:kotlin-stdlib:${BuildConfig.kotlinVersion}")
    api(AndroidX.coreKtx)
    api(AndroidX.startup)
    api(AndroidX.constraintLayout)
    api(Other.material)

    api(Other.Retrofit.retrofit)
    api(Other.Retrofit.moshi)
    api(Other.okHttpLogger)
    api(Other.coroutineCore)
    api(Other.coroutineAndroid)
    ...
}

这里使用api是因为我在需要使用这个库的时候不需要从新添加依赖,用 implementation 只会在当前module。

Activity Result API

引用来自Google官方文档
While the underlying startActivityForResult() and onActivityResult() APIs are available on the Activity class on all API levels, it is strongly recommended to use the Activity Result APIs introduced in AndroidX Activity 1.2.0-alpha02 and Fragment 1.3.0-alpha02.

意思大概就是建议使用AndroidX 新的API来替换startActivityForResult() 和 onActivityResult()
因为项目中使用的是Navigation Component,所以对于需要onActivityResult的情况算是比较麻烦,这新的API就比较优雅得解决了这个问题。后续增加了权限申请的Contract,也是比较好用的东西。更多详情看 官网更新说明

MVVM

1. 对于MVVM架构想必大家都很熟悉了,MVVM拆分成M/V/VM, 分别对应Model-View-ViewModel

  • Model,我喜欢把它理解成是用来渲染界面(也就是View)的一个状态或者属性吧,用来驱动界面各组件的渲染结果的一个东西
  • View,往细的讲,其实它也是android.view中的View。往大点的讲,也就是大多数人理解的Fragment/Activity,其实我觉得Fragment/Activity就是android.view中View的容器。 反正不管是Fragment/Activity还是View,都是用来展示给用户看的。
  • ViewModel,看名字,是前两个组合而成的一个词,所以理解成是View和Model之间的红线。在以前没有LiveData的时候,这一层都是需要持有一个ViewInterface接口来驱动数据Model和View之间的关系,如今由了LiveData,这里只需要一个数据来源,然后配合LiveData驱动Fragment/Activity中的View渲染。所以数据源可以提取成Repository/DataSource层,主要管理数据是从Remote还是LocalDB。

2. 最后,对于MVVM,我都是持有一下想法来使用:

  • View不需要任何逻辑(一个Boolean变量驱动View显示或者隐藏这种小的我觉得还是可以接受,但是也可以提取到ViewModel中用一个方法来map成View.GONE/View.VISIABLE)。
  • Model这层吧,可以根据界面需要来进行定义,考虑公用或者特有进行封装,也可以想成MVI中的State,因为View的渲染需要Model来驱动的。
  • ViewModel只在乎数据来源的结果,无需了解从何而来,拿到结果通过LiveData配合Model驱动View渲染就好。

如有不对,欢迎指出

参考链接

【奇技淫巧】除了 buildSrc 还能这样统一配置依赖版本?巧用 includeBuild