首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

你应该知道的 Android 网络访问方式的演化史

作者:Elye编译者:Kotlin之巅

众所周知,Android 不知不觉间已经存在超过 10 年了,与此同时,Android 开发者们访问网络的方式也在不断演化中。本文我将通过一个例子来简单分享我对这个演化的认识。

恐龙时代:直接访问

在 Android 2.2 版本之前,网络访问相关的代码和其他代码一样,可以在主线程中直接使用,不会导致任何异常:

然而,这种用法体验并不理想,因为网络访问相对 UI 交互来说通常很慢,视具体的接口而定,通常需要几秒钟时间,这段时间内 UI 界面会卡住,用户体验比较糟糕。因此,在后面的版本中,如果你在主线程中访问网络,Android应用在运行时将会毫不留情的抛出 异常,导致应用闪退。

当然也还是有一些办法可以强制 Android 允许在主线程中直接访问网络,就像本文这个例子中一样,但这种操作仅仅用于演示目的,千万不要在任何线上产品中使用。

石器时代:使用子线程

稍微有点经验的开发者应该都知道,为了不阻塞 UI 交互,我们可以把网络访问部分代码放到后台线程中,这样就能够在访问网络获取数据的同时能够有流畅的 UI 响应。示例代码如下所示:

上面的代码是在子线程中访问网络的基本方式,需要注意的一点是,更新 UI 界面的代码必须是放到主线程中,也就是通过使用主线程的 来创建 Handler,否则会出现 异常。

这种方式有很多不足之处,因为线程的管理通常比较复杂,让开发者直接处理这种线程问题可能会导致写出来的 App 存在出错的风险,因此,Google 做了进一步的优化。

青铜时代:AsyncTask

由于主线程已经禁用直接访问网络,因此,Google 提出了一种推荐的方法,称为 AsyncTask。

AsyncTask 带来了很多不错的特性,例如在后台线程中执行网络请求之前和之后,可以允许我们在主线程执行某些操作,同时,它也支持渐进式的更新等。示例代码如下所示:

曾几何时,这种方式被称为标准的网络访问方式,网络上也能找到相关的教程。

尽管 AsyncTask 是 Google 引入的,但开发者们陆续发现它的一些缺陷,特别是跟 Android 应用生命周期相关的,具体可以参考 The Hidden Pitfalls of AsyncTask 这篇文章。

因此,尽管曾经是标准方式,但现在已经没什么人用它了。

中世纪:IntentService

由于 AsyncTask 不尽如人意,另外一个流行的方式出现了,它就是 IntentService。

当然,IntentService 并不是 Google 专门引入用来解决 AsyncTask 缺点的,它最初是为了后台长时间运行的服务(例如文件下载)而设计的。

随着社区对 AsyncTask 的摒弃,开发者们开始考虑将 IntentService 作为替代方案。

使用简单的代码片段很难讲清楚这种方式,因此我们来看下面这张图。IntentService 位于 Activity 之外,它本质上是一个 Service,需要注册到 AndroidManifest 中。

我们可以把 IntentService 当作一个线程,网络访问代码如下所示:

可以看到,当网络访问完成后,它通过 BroadcastReceiver 发送消息给 Activity 来实现结果信息的传递。

因此,虽然这种方式可以作为替代方案,但相对来说属于重量级的方式,如果我们只是想要发起一个简单的网络请求,这种方式显得太过笨重。

工业时代:RxJava

随着函数式编程和响应式编程的流行,RxJava 也被引入了 Android 社区。

很快的,网络访问的标准方式变成了 RxJava。

这种方式之所以流行,是因为它通过链式调用的方式把主线程和子线程的操作串联起来。

我想如果有人声称自己在使用 RxJava,那么很大可能他只是在项目中网络访问部分的代码中使用 RxJava,其他地方的代码根本就没有使用 RxJava 这种函数响应式编程范式。

这种现象的原因是响应式编程本身是一个相对比较复杂的概念,不好掌握,而且需要使用匿名类(因为当时 Android 开发中只能使用 Java 6 和 Java 7),因此代码写起来并不是很顺畅。

现代:RxJava + Kotlin

2017 年,Google 宣布在 Android Studio 中对 Kotlin 语言提供一级公民形式的支持,这使得使用 Kotlin 开发 Android 迅速流行起来。使用 Kotlin 中的 lambda 表达式代替 Java 中匿名类,使得 RxJava 的使用更加简洁。

让我们来看看实现相同功能的网络访问代码使用 Kotlin 改写后的形式:

可以看到,实现相同功能的代码简练了很多。因此,在 Kotlin 中,RxJava 方式访问网络变得更加流行,出现了越来越多有趣且优雅的使用 RxJava 访问网络的方式。具体可以参考这两篇文章:《RxJava: Clean way of prefetching data and use later》,《Managing Network State using RxJava》。

未来:Coroutines

尽管 RxJava 解决了很多问题,但它的学习曲线对很多初学者来说还是很陡峭的。响应式编程范式对多数使用者来说会显得有点别扭,源头(网络获取的数据)和结果(发送给 UI 界面显示的数据)之间的联系看起来并不直接。

最新版本的 Kotlin 引入了 Coroutines,虽然现在还处于试验阶段,但它看起来前景广阔。

Coroutines 最大的亮点是使得异步代码看起来像同步代码,如下所示:

如果你想代码变得更优雅,例如使用 future 或者 promises 之类的概念使得代码更具响应式的特点,那么也可以通过 async-await 的方式来编写:

因此,在我看来,Coroutines 很好的桥接了初学者社区和资深的专家。这里有一篇不错的文章(《Simple asynchronous loading with Kotlin Coroutines》)将 Kotlin 的 Coroutines 和 Android 的生命周期 API 相结合。结合后代码示例如下:

看起来前景广阔吧,以上是我对未来几个月 Android 网络访问方式的预测,如果你有其他想法,欢迎交流。

参考文档

原文链接:https://medium.com/@elye.project/the-evolution-of-android-network-access-1e199fc6e9a2

本文示例代码地址:https://github.com/elye/demoandroidnetwork_evolution

AsyncTask:https://developer.android.com/reference/android/os/AsyncTask.html

The Hidden Pitfalls of AsyncTask:http://blog.danlew.net/2014/06/21/the-hidden-pitfalls-of-asynctask/

RxJava: Clean way of prefetching data and use later:https://medium.com/@elye.project/rxjava-clean-way-of-prefetching-data-and-use-later-54800f2652d4

Managing Network State using RxJava:https://medium.com/@elye.project/managing-network-state-using-rxjava-79cdaed88d5d

Simple asynchronous loading with Kotlin Coroutines:https://hellsoft.se/simple-asynchronous-loading-with-kotlin-coroutines-f26408f97f46

Android 生命周期 API:https://developer.android.com/topic/libraries/architecture/lifecycle.html

  • 发表于:
  • 原文链接http://kuaibao.qq.com/s/20180126G0UCEK00?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券