https://jqs7.com/kotlin-retrofit-rxandroid-realm/

原作者:Ahmed Rizwan

原文链接:Kotlin : Retrofit + RxAndroid + Realm

译文作者:Jqs7

审阅:@SusuwANjr

在这篇文章里面我会使用一些库(就我平时用那些),比如使用 Kotlin 和 Rx 来写 Retrofit 和 Realm 。

如果你是个 Retrofit 新手……建议你阅读一下这篇文章——保证亮瞎你狗眼让你眼前一亮!如果你不知道 Rx & Kotlin —— 看这里!

那我们开始吧:Kotlin + Rx + Retrofit + Realm 如果你像我一样,那一定很讨厌一大片的冗余的代码 咳咳 Java6 。自我开始从事安卓开发以来,经常遇到一些“什么鬼?!”的问题。

在语言上我觉得 Kotlin 大法就是好!像 Retrofit ,Realm 以及 RxAndroid 这些库真心省了不少代码。

蜀黍给你讲个可怕的故事:有次我负责一个项目,里面有 12 个 POJO 类,还有 12 个数据库表类(ORM),还有 12 个数据库模型映射类。如果你数学学得好的话,你就会发现……特喵的有 36 个类!还不只是这样,如果要改一个类,那就意味着 3 个类全都得改。

我当时就这表情…

如果我们不用 ORM 的话,我们还得去写模型到数据库的映射类,真特么得吓尿我!

所以解决办法是啥?对我来说就是 Realm + Retrofit 啦 (^o^)ノ 我还用了 RxAndroid ,因为有了 Rx 生活更美好,当然还有 Kotlin ,因为……

Kotlin 大法好!Kotlin 千秋万代,一统江湖!

把这些东西结合起来,那 36 个类所做的事情只要 12 个类就能完成了 (本来就应该这样嘛 (ゝ∀・))。不光这样,代码也会因为 Kotlin 而变得更加简洁,表达性更为良好!

小例子:从 Github API 获取数据

一个常见的应用场景:从 API 获取数据,把数据存储到数据库并显示出来。

完成品就像下图这样,只是一个很简单的例子……希望可以覆盖到基本的姿势点!

下面就讲讲该怎么把这个 app 给撸出来……

创建项目并启用 Kotlin

创建完项目我们做的第一件事就是启用 Kotlin ——首先要在 Android Studio 里面装好 Kotlin 插件。

我创建了一个只有一个 MainActivity 的空项目——直接打开 build.gradle 文件,然后打开 action 列表(快捷键 ctrl+shift+a)

吼的!我们现在可以用 Kotlin 来写代码了!

现在的 MainActivity,标准格式,木有惊喜

我们可以像下面这样把 java 代码转成 Kotlin

现在 MainActivity 变成了下面这样……

Holy mother of Kotlin!

添加 Rx — Retrofit — Realm 依赖

    //Realm
compile 'io.realm:realm-android:0.87.4'
//RxAndroid
compile 'io.reactivex:rxandroid:1.1.0'
compile 'io.reactivex:rxjava:1.1.0'
//RxBindings
compile 'com.jakewharton.rxbinding:rxbinding:0.3.0'
//Retrofit
compile 'com.squareup.retrofit:retrofit:2.0.0-beta2'
//Retrofit Adapter and Converter
compile 'com.squareup.retrofit:adapter-rxjava:2.0.0-beta2'
compile 'com.squareup.retrofit:converter-gson:2.0.0-beta2'
//Glide
compile 'com.github.bumptech.glide:glide:3.7.0'
//Databinding and Realm Annotations
kapt 'com.android.databinding:compiler:1.0-rc4'
kapt "io.realm:realm-annotations:0.87.4"
kapt "io.realm:realm-annotations-processor:0.87.4"

我还使用了 Databinding !因为用 Databinding 的人比较帅 (ゝ∀・)

你大概想问: kapt 是什么鬼?好吧,它是Kotlin内置的注解处理器。

把这个添加到 build.gradle

在这个项目里面我还得把 kapt 的 generateStubs 给打开,因为要用它来生成代码。

万事俱备!开始写代码啦!

Model

我们使用的 API 地址是:

https://api.github.com/users/ahmedrizwan

服务端返回的内容如下:

    {
"login": "ahmedrizwan",
"id": 4357275,
"avatar_url": "https://avatars.githubusercontent.com/u/4357275?v=3",
"gravatar_id": "",
"url": "https://api.github.com/users/ahmedrizwan",
"html_url": "https://github.com/ahmedrizwan",
"followers_url": "https://api.github.com/users/ahmedrizwan/followers",
"following_url": "https://api.github.com/users/ahmedrizwan/following{/other_user}",
"gists_url": "https://api.github.com/users/ahmedrizwan/gists{/gist_id}",
"starred_url": "https://api.github.com/users/ahmedrizwan/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/ahmedrizwan/subscriptions",
"organizations_url": "https://api.github.com/users/ahmedrizwan/orgs",
"repos_url": "https://api.github.com/users/ahmedrizwan/repos",
"events_url": "https://api.github.com/users/ahmedrizwan/events{/privacy}",
"received_events_url": "https://api.github.com/users/ahmedrizwan/received_events",
"type": "User",
"site_admin": false,
"name": "ahmed",
"company": null,
"blog": null,
"location": "Rawalpindi, Pakistan",
"email": null,
"hireable": null,
"bio": null,
"public_repos": 9,
"public_gists": 0,
"followers": 5,
"following": 9,
"created_at": "2013-05-06T18:32:59Z",
"updated_at": "2015-08-29T18:17:58Z"
}

在这个例子里面,只要把 id, name, avatarurl 和 publicrepos 从返回信息里面提取出来就够了。所以 model 类就像下面这样(同时也是个 realm 类):

    @RealmClass
open class Github : RealmObject() { @PrimaryKey
@SerializedName("id")
@Expose
open var id: Int = 0 @SerializedName("avatar_url")
@Expose
open var avatarUrl: String? = null @SerializedName("name")
@Expose
open var name: String? = null @SerializedName("public_repos")
@Expose
open var publicRepos: Int? = null }

小提示:如果你需要JSON返回的所以属性的话,我建议你使用这个网站来生成一个 POJO 类,再像上面说的那样把 Java 代码转成 Kotlin 代码。

我们就用 RealmClass 注解说起吧,在 Kotlin 中需要为 Realm model 类加上这个注解,Realm 才能生成 Realm 代理类,PrimaryKey 也是一个 Realm 注解,表示主键属性(废话),剩下的就是 Gson 注解了……

open关键字正好跟 Java 里面的 final 相反。默认情况下,Kotlin 的类就是 final 的,如果你如果要一个类可以被继承,就必须把它声明为 open。这对于属性也是一样的,比如上面的 model 类里面,name 这个属性,它拥有一个 getter 和 setter,为了使它们可以被重写(因为 Realm 需要),我们就得在属性的前面加上 open 关键字。

Retrofit 接口

因为我们的端点地址是:

https://api.github.com/users/[some_user]

所以接口写出来就是下面这样:

interface GithubService {
@GET("users/{username}")
fun getGithubUser(@Path("username") username: String): Observable<Github>
}

上面我们直接返回了一个 Observable 的 Github,因为 Retrofit 集成了 Rx,简直就是碉堡了!

Retrofit Builder

val gson = GsonBuilder().setExclusionStrategies(object : ExclusionStrategy {
override fun shouldSkipField(f: FieldAttributes): Boolean {
return f.declaringClass == RealmObject::class.java
} override fun shouldSkipClass(clazz: Class<*>): Boolean {
return false
}
}).create() val retrofit: Retrofit = Retrofit.Builder()
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create(gson))
.baseUrl("https://api.github.com/")
.build() val githubService: GithubService = retrofit.create(
GithubService::class.java)

因为用了 Realm ,所以我们得重新声明一个 Gson 实例,添加排除策略(exclusion strategy)来跳过Realm生成的属性,不然 Gson 对于这个 model 就没什么卯月了。

在下面就是一个加入 RxJavaCallAdapter 工厂类启用 Rx 集成的 Retrofit 实例,我们还加了一个使用了上面创建的 Gson 实例的 Gson 解析器。

Rx 魔法

  githubService.getGithubUser("ahmedrizwan")
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
{ user ->
realm.beginTransaction()
realm.copyToRealmOrUpdate(user)
realm.commitTransaction()
updateViews(binding, user)
},
{ error ->
Log.e("Error", error.message)
}
)

现在我们所做的就是:获取 observable 对象,订阅之,并获取 Github 对象。只有一获取到 Github 对象,就可以很简单的把用户保存到 Realm 数据库里面了。

缓存

缓存也是可以有的 (=゚ω゚)=,我们可以一开始就可以获取 Realm 数据库里面的数据(如果存在的话),就像下面这样:

    val realm = Realm.getDefaultInstance()

    //get user if it's already saved
val savedUser: Github? = RealmQuery.createQuery(realm,
Github::class.java).findFirst()
updateViews(binding, savedUser)

到这里就已经差不多完成了,接下来就差运行…

鼓个掌

你可以在这里找到这个例子的所有代码,希望这篇文章对你有所帮助。

Happy coding!

Kotlin : Retrofit + RxAndroid + Realm的更多相关文章

  1. Android网络请求框架之Retrofit实践

    网络访问框架经过了从使用最原始的AsyncTask构建简单的网络访问框架(甚至不能称为框架),后来使用开源的android-async-http库,再到使用google发布的volley库,一直不懈的 ...

  2. 【我的Android进阶之旅】Realm数据库学习资料汇总(持续更新)

    介绍 realm是一个跨平台移动数据库引擎,支持iOS.OS X(Objective-C和Swift)以及Android. 2014年7月发布.由YCombinator孵化的创业团队历时几年打造,是第 ...

  3. MVP实战心得—封装Retrofit2.0+RxAndroid+RxBus

    响应式编程框架,rxjava的扩展,很爽的链式编程 魅力在于对数据的处理,与线程切换的灵活性. 用来处理异步操作(Lambda表达式不会用.用Lambda表达式代码会更少,但不会的人会看不懂代码.不是 ...

  4. 我的Android进阶之旅------>RxJava学习资料汇总

    在响应式编程中,应该牢记以下两点: everything is a stream(一切皆流) don't break the chain(不要打断链式结构) 记住,可观测序列就像一条河,它们是流动的. ...

  5. 不可错过的几款GitHub开源项目

    工作之余或者周末感觉无聊?不知道干什么?想继续提高技术,但是不知道做什么的同学,看过来,不妨利用闲暇时间来撸几个 GitHub 上还不错的开源项目,本文推荐的开源项目比较适合新手.及对MVP设计模式不 ...

  6. 【转】Android开发规范

    转自:https://github.com/Blankj/AndroidStandardDevelop 摘要 1 前言 2 AS 规范 3 命名规范 4 代码样式规范 5 资源文件规范 6 版本统一规 ...

  7. 【转】Android 开发规范(完结版)

    摘要 1 前言 2 AS 规范 3 命名规范 4 代码样式规范 5 资源文件规范 6 版本统一规范 7 第三方库规范 8 注释规范 9 测试规范 10 其他的一些规范 1 前言 为了有利于项目维护.增 ...

  8. Android 你应该注意的开发规范

    本文由Blankj投稿. Blankjd的博客地址: http://www.jianshu.com/u/46702d5c6978 为了利于项目维护以及规范开发,促进成员之间Code Review的效率 ...

  9. android -------- Retrofit + RxJava2.0 + Kotlin + MVP 开发的 WanAndroid 项目

    简介 wanandroid项目基于 Retrofit + RxJava2.0 + Kotlin + MVP 用到的依赖 implementation 'io.reactivex.rxjava2:rxj ...

随机推荐

  1. Linux驱动基础:MSM平台AP/CP通信机制

    点击打开链接 概述 MSM平台AP和CP封装到一个芯片,共享内容.所以之前也说过,高通的MSM解决方案中,CP的代码都是由AP放到指定地址的内存中以供CP运行.那上传完代码,CP开始跑之后,AP/CP ...

  2. iOS中 UITabBarController中自定义UITabBar

    1.创建多个视图控制器,放如UITabBarController中 AViewController *aa = [[AViewController alloc] init]; UINavigation ...

  3. 并发编程(三): 使用C++11实现无锁stack(lock-free stack)

    前几篇文章,我们讨论了如何使用mutex保护数据及使用使用condition variable在多线程中进行同步.然而,使用mutex将会导致一下问题: 等待互斥锁会消耗宝贵的时间 - 有时候是很多时 ...

  4. Android进程通信之一:两种序列化方式

    2月下旬辞职了,去海南度假到现在,领略了一把三亚风情也算任性和 然而这样任性带来的后果就是..不行了我必须吐槽一句.. 没毕业的找工作就这么难嘛!投了57家一家面试机会都没有,好歹给个面试机会啊!!本 ...

  5. wing带你玩转自定义view系列(2) 简单模仿qq未读消息去除效果

    上一篇介绍了贝塞尔曲线的简单应用 仿360内存清理效果 这一篇带来一个  两条贝塞尔曲线的应用 : 仿qq未读消息去除效果. 转载请注明出处:http://blog.csdn.net/wingicho ...

  6. 树莓派linux驱动学习之LED控制

    前面我们编写了hello world的程序,接下来继续研究GPIO功能,通过GPIO来控制LED的亮灭,这在单片机中应该算是十分简单的一个程序了,但是在Linux系统中控制GPIO没有那么简单,难点就 ...

  7. 【Android 应用开发】Android开发技巧--Application, ListView排列,格式化浮点数,string.xml占位符,动态引用图片

    一. Application用途 1. Application用途 创建Application时机 : Application在启动的时候会调用Application无参的构造方法创建实例; Appl ...

  8. node.js 的url模块

    var URL = require('url');  var testUrl = "http://www.baidu.com:8080/index.php?content=abc" ...

  9. Unix/Linux中的fork函数

    fork函数介绍 一个现有进程可以调用fork函数创建一个新进程.该函数定义如下: #include <unistd.h> pid_t fork(void); // 返回:若成功则在子进程 ...

  10. 【Visual C++】游戏编程学习笔记之五:单一背景滚动

    本系列文章由@二货梦想家张程 所写,转载请注明出处. 本文章链接:http://blog.csdn.net/terence1212/article/details/44224963 作者:ZeeCod ...