原文链接:轻松搭建基于JetPack组件的MVVM框架 - 掘金

Brick

github gitee

介绍

辅助android开发者搭建基于JetPack组件构建MVVM框架的注解处理框架。通过注解自动生成ViewModel的Factory类、lazy方法等;支持在项目的任意位置注入ROOM的dao层接口与Retrofit库中的api接口。

特点

android开发者可以将brick理解为一个轻量级的注入框架,使用非常简单,使用4-6个注解即可工作。brick主要在编译期工作, 不会在App运行时产生任何额外的性能消耗 ,并且只有1个注解库会打包到你的android工程中,不用担心体积增大的问题。

适用范围

  1. 使用androidx而非support库。
  2. 使用JetPackViewModel组件。
  3. 使用Retrofit作为网络请求库。
  4. 使用ROOM数据库框架。(可选)
  5. 服务端为多端口、多IP的项目。(可选)

引入

  1. 在你的android工程的根目录下的build.gradle文件中的适当的位置添加以下代码:
buildscript {...ext {brick_version = '0.2.0'}repositories {...maven { url 'https://jitpack.io' }}dependencies {classpath "com.gitee.numeron.brick:plugin:$brick_version"}
}allprojects {repositories {...maven { url 'https://jitpack.io' }}
}
复制代码

  1. 在你的android工程中要启用brick的android模块的build.gradle文件中的适当位置添加以下代码:
...
apply plugin: 'kotlin-kapt'
apply plugin: 'brick'
...
dependencies {...implementation "com.gitee.numeron.brick:annotation:$brick_version"kapt "com.gitee.numeron.brick:compiler:$brick_version"
}
复制代码

使用

一、 @Provide注解的使用方法:

  1. 在你编写好的ViewModel子类上添加@Provide注解
@Provide
class WxAuthorViewModel: ViewModel() {...
}
复制代码

  1. 有3种方式让brick注解处理器开始工作:
  • 在Terminal终端上输入gradlew :[ModuleName]:kaptDebugKotlin运行脚本;
  • 在AndroidStudio右侧Gradle扩展栏中依次找到[PrjectName] -> [ModuneName] -> Tasks -> other -> kaptDebugKotlin并双击运行脚本;
  • Ctrl + F9编译整个项目。以上三种方式任选其一即可运行brick注解处理器。
  1. 脚本运行结束后,会生成两个包级方法:
  • lazyWxAuthorViewModel()扩展方法,在Activity或Fragment中直接调用即可。
  • get()方法,在不方便使用lazy方法时,可使用此方法获取ViewModel的实例。注:lazyWxAuthorViewModel方法就是对get()方法的包装。
    直接使用生成的方法,即可创建对应的ViewModel实例:
private val wxAuthorViewModel by lazyWxAuthorViewModel()
复制代码

或在onCreate()之后,通过get创建:

private lateinit var wxAuthorViewModel: WxAuthorViewModeloverride fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)wxAuthorViewModel = get(this)
}
复制代码

二、 @Inject注解的使用方法

-2. (必需) 在获取Retrofit实例的方法上添加@RetrofitInstance,如:

@RetrofitInstance
val retrofit: Retrofit by lazy(LazyThreadSafetyMode.SYNCHRONIZED) {Retrofit.Builder().client(okHttpClient).baseUrl(WANDROID_BASE_URL).addConverterFactory(MoshiConverterFactory.create()).build()
}val okHttpClient: OkHttpClient by lazy(LazyThreadSafetyMode.SYNCHRONIZED) {val logInterceptor = HttpLoggingInterceptor()logInterceptor.level = HttpLoggingInterceptor.Level.BODYOkHttpClient.Builder().addInterceptor(logInterceptor).callTimeout(15, TimeUnit.SECONDS).readTimeout(60, TimeUnit.SECONDS).writeTimeout(60, TimeUnit.SECONDS).connectTimeout(15, TimeUnit.SECONDS).build()
}
复制代码

注:@RetrofitInstance注解只能标记在public修饰的val属性上或方法上,val属性上或方法可以在object 单例companion object中,也可以是包级属性/方法。

-1. (可选) 在获取RoomDatabase实例的属性或方法上标记@RoomInstance,如:

@RoomInstance
val wandroidDatabase: WandroidDatabase by lazy(LazyThreadSafetyMode.SYNCHRONIZED) {Room.databaseBuilder(CONTEXT, WandroidDatabase::class.java, "wandroid.db").build()
}
复制代码

注:@RoomInstance注解只能标记在public修饰的val属性上或方法上,val属性上或方法可以在object 单例companion object中,也可以是包级属性/方法。

  1. 假设已有Retrofit Api接口和WxAuthorRepo
interface WxAuthorApi {@GET("wxarticle/chapters/json  ")suspend fun getWxAuthorList(): List<WxAuthor>
}class WxAuthorRepo {...
}复制代码

  1. 在WxAuthorRepo中添加lateinit var修饰的WxAuthorApi字段,并用@Inject标记:
class WxAuthorRepo {@Injectlateinit var wxAuthorApi: WxAuthorApi}
复制代码

  1. 在ViewModel中创建lateinit var修饰的WxAuthorRepo字段,并用@Inject标记:
@Provide
class WxAuthorViewModel: ViewModel() {@Injectprivate lateinit var wxAuthorRepo: WxAuthorRepo
}
复制代码

标记后,继续编写业务代码即可,所有被@Inject标记的字段,都会在编译期自动获取或创建实例,无需担心它们在何时被赋值。注:虽然是lateinit var修饰的字段,但是不要尝试为它们赋值,这会导致致命的错误。注:@Inject可以注入的类型只有Retrofitapi接口和ROOMdao接口、以及有无参构造的类。

三、 多服务器或多端口的处理方法:

假设有另一个Retrofit api接口,它的访问地址或端口与baseUrl中的不一样,此时,可以在Retrofitapi接口上添加@Port@Url注解来设置它们的url或port。

  1. @Port的使用:
@Port(1080)
interface ArticleApi {@GET("wxarticle/list/{chapterId}/{page}/json")suspend fun getArticleList(@Path("chapterId") chapterId: Int, @Path("page") page: Int): Paged<Article>}
复制代码

添加此注解后,brick会在编译期根据@RetrofitInstance注解标记的Retrofit实例和@Port的端口号,重新创建一个Retrofit实例,并使用新的Retrofit实例创建ArticleApi的实例。

  1. @Url的使用:
@Url("http://www.wanandroid.com:1080/")
interface ArticleApi {@GET("wxarticle/list/{chapterId}/{page}/json")suspend fun getArticleList(@Path("chapterId") chapterId: Int, @Path("page") page: Int): Paged<Article>
}
复制代码

@Port的使用基本一致,实现的原理也是一样的。

附录1

生成的WxAuthorViewModels.kt文件:

//kotlin 扩展方法,在Activity/Fragment中通过by调用
fun ViewModelStoreOwner.lazyWxAuthorViewModel(): Lazy<WxAuthorViewModel> =LazyWeChatAuthorViewModel(this)//包级方法,在Activity/Fragment的onCreate方法之后调用
fun get(owner: ViewModelStoreOwner): WxAuthorViewModel {val factory = WxAuthorViewModelFactory()return ViewModelProvider(owner, factory).get(WxAuthorViewModel::class.java)
}private class WxAuthorViewModelFactory : ViewModelProvider.Factory {@Suppress("UNCHECKED_CAST")override fun <VM : ViewModel> create(clazz: Class<VM>): VM = WxAuthorViewModel() as VM
}private class LazyWxAuthorViewModel(private val owner: ViewModelStoreOwner
) : Lazy<WxAuthorViewModel> {private var _value: WxAuthorViewModel? = nulloverride val value: WxAuthorViewModelget() {if(_value == null) {_value = get(owner)}return _value!!}override fun isInitialized(): Boolean = _value != null
}
复制代码

附录2

反编译后的WxAuthorViewModel.class:

class WxAuthorViewModel extends ViewModel {private final WxAuthorRepo wxAuthorRepo = new WxAuthorRepo();}
复制代码

附录3

反编译后的WxAuthorRepo.class:

class WxAuthorRepo {private final WxAuthorApi wxAuthorApi = RuntimeKt.getRetrofit().create(WxAuthorApi.class);public final WxAuthorApi getWxAuthorApi() {...return wxAuthorApi;}}
复制代码

附录4

WxAuthorApi添加@Port注解后的WxAuthorRepo.class:

class WxAuthorRepo {private final WxAuthorApi wxAuthorApi = newRetrofit(RuntimeKt.getRetrofit(), 1080, null).create(WxAuthorApi.class);public final WxAuthorApi getWxAuthorApi() {...return wxAuthorApi;}private final Retrofit newRetrofit(Retrofit retrofit, int port, String url) {if (port > 0) {HttpUrl httpUrl = retrofit.baseUrl().newBuilder().port(port).build();return retrofit.newBuilder().baseUrl(httpUrl).build();} else if(url != null && url.length() != 0) {return retrofit.newBuilder().baseUrl(url).build();}return retrofit;}}
复制代码

总结

通过反编译class后的代码以及整篇文章后可以得出一个大概的结论:brick就是在java编译成class后,class编译成dex之前,对class的字节码进行修改,给@Inject标记的字段赋值,实现的注入框架。 目前对ViewModel的注入还需要手动调用生成的方法来初始化,这在编译代码之前,AS上都会有红色的错误标记,接下来,让@Inject支持ViewModel的创建就是主要工作啦,等完成后,再发文章吧。## 写在最后


我意识到有很多经验和知识值得分享给大家,也可以通过我们的能力和经验解答大家在IT学习中的很多困惑,所以在工作繁忙的情况下还是坚持各种整理和分享。但苦于知识传播途径有限,很多程序员朋友无法获得正确的资料得到学习提升,故此将并将重要的Android进阶资料包括自定义view、性能优化、MVC与MVP与MVVM三大框架的区别、NDK技术、阿里面试题精编汇总、常见源码分析等学习资料免费分享出来。

知识不体系?这里还有整理出来的Android进阶学习的思维脑图,给大家参考一个方向。包含知识脉络 + 诸多细节,由于篇幅有限,下面只是以图片的形式给大家展示一部分。

【Android学习PDF+学习视频+面试文档+知识点笔记】

【Android高级架构视频学习资源】

Android部分精讲视频领取学习后更加是如虎添翼!进军BATJ大厂等(备战)!现在都说互联网寒冬,其实无非就是你上错了车,且穿的少(技能),要是你上对车,自身技术能力够强,公司换掉的代价大,怎么可能会被裁掉,都是淘汰末端的业务Curd而已!现如今市场上初级程序员泛滥,这套教程针对Android开发工程师1-6年的人员、正处于瓶颈期,想要年后突破自己涨薪的,进阶Android中高级、架构师对你更是如鱼得水,赶快领取吧!

【Android进阶学习视频】、【全套Android面试秘籍】可以简信我【学习】查看免费领取方式!

android mvvm框架搭建_轻松搭建基于JetPack组件的MVVM框架相关推荐

  1. vsscode beego 没有提示_轻松搭建基于 Serverless 的 Go 应用(Gin、Beego 举例)

    首先介绍下在本文出现的几个比较重要的概念: 函数计算(Function Compute): 函数计算是一个事件驱动的服务,通过函数计算,用户无需管理服务器等运行情况,只需编写代码并上传.函数计算准备计 ...

  2. thinkphp v5.0.24 密码爆破_轻松搭建基于 Serverless 的 ThinkPHP 应用

    首先介绍下在本文出现的几个比较重要的概念: 函数计算(Function Compute): 函数计算是一个事件驱动的服务,通过函数计算,用户无需管理服务器等运行情况,只需编写代码并上传.函数计算准备计 ...

  3. java框架谁搭建_从零开始搭建一个开发框架(Java + Hibernate + Spring + Oracle)

    框架使用的系统技术以及数据库如下: 技术:Java/Hibernate/Hibernate Annotation/Spring 数据库:Oracle 10g 整个框架的搭建步骤大致分为以下三步: 1. ...

  4. mysql双机热备 读写分离_轻松搭建MySQL主从复制、读写分离双机热备)

    注意:如果此步骤始终为空设置(0.00秒),则表示先前的my.cnf配置不正确,请返回并重试检查配置步骤. (从)数据库中的配置 1.修改从属库的数据库配置文件 [root @ localhost]# ...

  5. e盘是否具有读写权限_轻松搭建MySQL主从复制、读写分离(双机热备)

    主从复制: 当mysql数据库的数据量太大的时候,查询数据就很吃力了,无论怎么优化都会产生瓶颈,这时我们需要增加服务器设备来实现分布式数据库,实现多机热备份,要想实现多机的热备,首先要了解主从数据库服 ...

  6. mysql双机热备 读写分离_轻松搭建MySQL主从复制、读写分离(双机热备)

    主从复制: 当mysql数据库的数据量太大的时候,查询数据就很吃力了,无论怎么优化都会产生瓶颈,这时我们需要增加服务器设备来实现分布式数据库,实现多机热备份,要想实现多机的热备,首先要了解主从数据库服 ...

  7. jenkins搭建_如何搭建移动端自动化测试平台?没错,就用Jenkins!

    环境搭建 stf和Jenkins的安装过程这里不做说明,可以网上查找资料,这里只说一下注意的地方和需要的插件以及插件的配置. stf环境搭建 stf的环境搭建坑比较多,对node和npm的版本不对会出 ...

  8. 虚拟ip是什么意思_轻松了解基于Ip,Mac,组播的Valn是什么意思,通信基础第17篇...

    通信知识第17篇:在上一篇中介绍了一文轻松了解Mac引入Valn,老化机制,转发流程通信基础概念16 本节内容主要深入理解valn相关概念,接下来的章节会对二层通信知识点进行系统讲解. VLAN相关基 ...

  9. centos java服务器搭建_从零开始搭建CentOS 7服务器配置JavaWeb环境

    1.搭建FTP服务器 登录Linux,输入yum -y install vsftpd,安装vsftpd软件 显示如下,即代表安装完成 配置vsftpd 输入vi /etc/vsftpd/vsftpd. ...

最新文章

  1. VM 下装ubuntu系统
  2. 在人脸识别的时候,一定要穿上衣服啊!
  3. 洛谷P2158仪仗队(数学,观察找规律,欧拉函数)
  4. 安装python3.9
  5. 知乎: 如何评价阿里开源的企业级 Node.js 框架 egg? #18
  6. vnc报错 font catalog is not properly configured
  7. python调用activateMQ进行数据传输
  8. 转载:从地理学透视中国现代化
  9. 一周信创舆情观察(6.15~6.21)
  10. 视频教程-CCNA之TCP/IP协议栈精讲-思科认证
  11. 数据库系统工程师怎么备考?
  12. FFmpeg入门详解之74:FFmpeg转码器Java版之需求规格说明书
  13. C# 读取TXT文本文档 搜索指定字符串所在的行 保存到集合
  14. windows server 2008 R2 怎么集成USB3.0驱动
  15. 单片机 STM32 HAL IO扩展 PCA9555
  16. 故障--桥接网卡的坑
  17. mysql列插入数据
  18. 老夫金钟罩铁布衫纵横江湖数十年
  19. 直接分享5个T的网盘资源
  20. 学生计算机测评安排,计算机系学生综合素质测评办法(修改)

热门文章

  1. 虚拟桌面启动后自动全屏
  2. JavaScript中map函数和filter的简单举例
  3. java String长度与varchar长度匹配理解(字符和字节长度理解)
  4. 三个简单的问题,让你顺势而为
  5. easyui select 下拉框的取值和赋值
  6. flash 游戏 ui 制作方案
  7. Python的matplotlib(2)
  8. 使用p3p跨域设置Cookie
  9. jquery 删除字符串最后一个字符的方法
  10. ibatis动态查询条件