美文网首页程序员产品
Android 开发中 API 层的最佳实践

Android 开发中 API 层的最佳实践

作者: cff70524f5cf | 来源:发表于2019-01-30 22:02 被阅读8次

    前言

    API层就是网络层,是一个App必不可少的模块。我从12年开始做安卓开发,从这些年的开发经验中对API层的实践进行一些总结,内容方面主要是围绕HttpClient的选择,响应处理的编程模型和通知UI数据更新的最佳方式。

    以下内容仅仅是个人观点,与实际内容如有出入,烦请指出;若喷,请轻点。

    SDK中的Http Client

    标题中的Http Client是一个泛指,可能与某个http请求库重名,它泛指所有的http请求客户端。

    SDK中的client有2个: HttpURLConnection和Apache的 HttpClient库。

    在最早的时候(大概Android1.x开始),SDK把Java的 HttpURLConnection照搬过来。但是 HttpURLConnection很底层,用起来非常麻烦。你发一个Get请求还要操作流,没有20行代码下不来,上传文件要自己拼 multi-part块,而且这个类在Android2.2之前还有内存泄漏的Bug。

    估计谷歌自己也不想用,就将Apache的 HttpClient库内置到SDK中了。在易用性上确实简洁不少,也实现了像 marti-part这种编码,不用我们手动拼了。但是缺点是太面向对象了,代码比较臃肿。发送Post请求,再加点Header,就要创建很多的对象,代码量依然下不来。于是当时诞生了很多针对HttpClient进行封装的类库,我用的最多的就是 android-async-http和 xutil。Android5.0之后,SDK将Apache的 HttpClient移除了。

    当然也有针对 HttpURLConnection进行封装的类库,比如谷歌自家的 Volley。Volley的性能优秀,且内置图片加载功能。当时风光过一阵,直到现在我仍然能看到有许多三方库http使用Volley来做。Volley的缺点是部分Http功能不完善,比如默认不能发送Post请求,需要手写一些代码;不支持重定向。

    现代化的Http Client

    Http Client的话题还没有说完,上面说到谷歌在2013年的IO大会上推了自家的Volley;但是会议上出现了一个小插曲:

    当谷歌的开发者在介绍Volley的时候,下面的某个听众喊道:

    "I prefer OkHttp。"

    当时引得众人大笑,介绍的人员值得很无奈的回了一句:"Yeah, I like OkHttp too."

    然后OkHttp就火了,好像Volley的介绍是为了让人们知道OkHttp。

    为什么OkHttp火?

    1.它功能完善:Http编码,协议和Http Verb的完全支持,Http Cache的完美支持

    2.它性能优越:它既没有基于 HttpURLConnection,也没有基于 HttpClient;自己用socket重新实现了一套。内置连接池,会重用连接,会选择最佳的Host,让网络延时降到最低

    3.它竟然支持拦截器这种现代化的网络功能

    4.它API简洁

    OkHttp是目前Android和Java平台最优秀的Http Client,没有之一。同时也诞生了基于OkHttp进行封装的三方库,比如: Okhttputils和 OkGo,它们使用起来都非常简单。 如果你喜欢注解,可以试试同一个团队出品的 Retrofit。

    顺便普及一下人员信息:

    Square公司:美国的一家做支付的公司,Okhttp和Retrofit的出品团队,团队有个大牛叫 JakeWharton。

    JakeWharton: Android界的顶尖大牛,现在去了谷歌,在做Kotlin方面的工作。很多人知道他写了ButterKnife,OkHttp,Retrofit,但是可能不知道当年谷歌团队的 support-v4包还没有支持属性动画的时候,人人都用他的 NineOldAndroid类库来做属性动画;当年谷歌团队的 support-v7包还没有出现的时候,人人都用它的 ActionBarSherlock来做ActionBar。真正的是一个人撑起一片天。

    响应处理的编程模型

    在Client的选择上,OkHttp是最佳选择。但是在响应处理的编程模型上,目前所有的Client都提供了Callback的模型来处理响应,用伪代码表示就是:

    回调的模型在代码复杂的时候回陷入 CallbackHell的问题,当然你可以用抽取方法来重构,也可以用RxJava来打平回调的层级;但在可读性方面仍然没有同步的代码看上去漂亮。来看一个同步模型的代码:

    显然同步模型会更具可读性,哪怕你异步逻辑再复杂,可读性都不会减少一点。如何能让同步的代码发送异步的请求呢?

    Java可以用Future来实现,更优雅的是Kotlin的协程。使用Kotlin协程的代码看起来像这样:

    Kotlin的Coroutine和其他语言的协程一样,拥有2大优点:更好的调度性能,异步代码变同步。这里不会讨论协程如何使用,只是用到了协程;如果要学习协程,最好的资源就是Kotlin官方网站。

    如何通知UI数据更新

    如果你的API层写在UI中,完全没有这个问题,但这显然不具有任何维护性和可扩展性。当我们将API单独抽出一个层(一般是MVP的P层)的时候,数据获取和处理的代码合UI分离了,必然面临这个问题。

    一般有3种处理方式:

    1.自定义Callback

    2.使用EventBus

    3.使用LiveData

    用自定义Callback的方式编写的代码看起来像这样:

    这种方式的需要每个逻辑都要自定义一个回调,代码量巨大,且丑陋,不可取。

    使用EventBus来通知UI,代码写起来想这样:

    可以看到,EventBus的方式让我们不用去定义大量的回调,换了种方式去定义大量的Event标识。当项目复杂后,可能有上百个Event标识,并不容易管理。所以这种方式不是最佳的方式。

    LiveData的方式代码写起来像这样:

    可以看到,LiveData的方式可以让我们避免去定义回调和Event的标识,写法上更简洁。更重要的是,LiveData天然能观察UI生命周期变化,能避免一些内存泄漏,以及在最佳时刻更新UI。

    MVP和MVVM

    客户端主要和UI打交道,最高效的架构一定是MVVM;前端的Vue和React已经完全证实了这一点。

    Android上的MVVM主要有3种实现:

    1.LiveData和ViewModel

    2.DataBinding

    3.基于Kotlin代理去实现VM层

    其中DataBinding需要学习一些特定语法,和前端的Vue很像,而且因为用了反射,在复杂的更新频率高的界面会有一点性能问题;不过也是很不错的一种选择。

    Kotlin天然支持属性代理,我们可以基于Kotlin的代理语法来实现UI的动态更新,不过这个需要一些精力。

    个人最喜欢的是LiveData和ViewModel。

    上个小节的Presenter层显示没有处理UI生命周期变化的逻辑,比如当UI结束时,Presenter是无法得知的,从而无法去释放一些资源。你可以手动去写一些代码,但是ViewModel是最佳选择,它天然可以监视UI销毁。所以换成ViewMode的代码是这样的:

    最佳实践

    综上所述,根据我个人经验得出的最佳实践是:选择OkHttp发送请求,使用Kotlin Coroutine处理响应,用LiveData来通知UI更新;将这些逻辑抽象为VM层,具体表现为ViewModel。

    网络请求本质上不就是从一个URL得到一个实体类吗?这样是不是更好一些呢?

    上面的代码使用我的开源库 AndroidKTX就可以做到。有人说,这么简单,那支持其他请求方式,设置全局Header,设置自定义拦截器,支持HTTPS吗?这些是一个网络库的基本功能,当然支持啦。

    AndroidKTX的Github地址是:https://github.com/li-xiaojun/AndroidKTX

    所以,贴下我项目中API层的实践代码:

    UI层的代码大概是这样:

    Android学习思维导图及资料

    需要这些资料的大伙关注+点赞+加群:185873940 免费获取!

    群内还有许多免费的关于高阶安卓学习资料,包括高级UI、性能优化、架构师课程、 NDK、混合式开发:ReactNative+Weex等多个Android技术知识的架构视频资料,还有职业生涯规划及面试指导。

    相关文章

      网友评论

        本文标题:Android 开发中 API 层的最佳实践

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