如何编写低碳环保的 Android 代码

如何写出低碳环保的 Android 代码

随着环境问题愈来愈严重,人们愈来愈重视低碳环保的生活方式。做为码农的咱们天然也应该为环保作出应有的贡献。那么什么是低碳环保,简而言之就是就是低能量、低消耗、低开支的生活方式,映射到咱们的工做中就是以最低的消耗的来完成组织交给咱们的任务。html

如下就以 Android 开发为例从库和语言两方面来讨论如何实现低碳环保的编程方式。java

从第三方库来讲

充分利用现存资源,尽量不重复造轮子。从以往来看,若是你对现存的轮子有各类不满试图从头写,那么最终结局中可能性最大的就是只写了部分后直接放弃转而成为某个轮子的支持者,写完且比现有轮子要好的可能性还不如转行去大学城门口卖炒面。固然若是你写的是就是 SDK 之类的基础工具,那仍是尽可能减小依赖为好。android

那么该如何挑选第三方库呢?Android 的应用层开发虽然使用 Java 语言,但并非 Java 上的库都适合 Android 开发。Android 使用的不是 Oracle JDK 也不是 Open JDK,而是 Google 改写过的 Apache Harmony JDK,不少 Oracle JDK 自带的类(特别是 javax 包下的)在 Android 中并不存在,因此使用这些方法的库 Android 不能使用。git

此外 Android 存在 65536 问题,这个坑体如今如下两点:程序员

1)Android 机器在应用的安装过程当中,系统会运行 dexopt 工具,将 .dex 文件优化为 .odex 文件,其中 dexopt 工具使用了固定的缓冲区大小来保存方法的元信息,低版本的 Android 机器上该缓冲区很是小,因此一旦方法数过多会直接致使 dexopt 崩溃,应用没法运行。github

2)Dalvik 指令集对于一个 .dex 文件只能保存 65536 个方法的索引,因此一个 .dex 文件即便能够拥有不少方法,可是那些多余的方法也都是没法运行的。详细信息能够阅读官方的 dalvik-bytecodeinvoke-kind {vC, vD, vE, vF, vG}, meth@BBBB 条目。mongodb

所以选择 Android 的第三库须要严格注意控制方法的总数量。编程

Android 经常使用库 vs J2EE 经常使用库

如下我总结了一些 J2EE 和 Android 上的经常使用库的对比以供参考,使用这些库能够有效提供编程效率,减小能量消耗:swift

功能 J2EE Android 备注
JSON 解析 Jackson Gson Jackson 功能全面,但太大;Gson 速度通常但胜在体积
Restful Jersey Retrofit Jersey 面向服务端,符合 JAX-RS 标准, Retrofit 面向客户端,不符合 JAX-RS 标准
依赖注入 Guice Dagger Guice 使用反射,Dagger 使用预编译,效率不是一个等级的
NoSQL MongoDB Realm Realm 兼容 Android,iOS,ReactNative,比起 Sqlite3 快得多
单元测试 JUnit Robolectric + Espresso JUnit 只能运行在 JVM 上,Robolectric 使 Android 代码能够运行在 JVM 上,Espresso 简化 UI 测试流程(虽然不少状况下 UI 测试没什么用)
异步调用 CompletableFuture/RxJava RxJava + RxAndroid + RxLifecycle 三合一基本是标配,除此以外还能够加上 RxBindingRxPermissionsRxAndroidAudio 等等组成完整的 Rx 你们族
网络请求 - OkHttp/Volley OkHttp 功能强大,Fluent API 能够写出更优秀的代码;Volley 代码量小容易扩展,有很是优秀的队列机制
时间处理 Java 8/Joda-Time - Java 原生时间处理 API 很是糟糕,所以 Java 8 直接加入了 Joda-Time。Joda-Time 虽然易用,但一个只是处理时间的库有 5000 多方法对于 Android 显然不实际,尽管有 joda-time-android 库但一般 Android 端须要处理时间代码很少,建议仍是直接调用难用的原生 API

其它方法

  • 构建良好的 Android 架构,尽可能将 Context 相关的一切和业务逻辑进行分离,使业务逻辑可以脱离于 UI 组件进行本地测试。MVC,MVP,MVVM,Flux 之类的只有适合本身才是最好的。也能够参考下 Google 最近开始编写的 Android 架构的示例代码,不得不说 Google 这一步作得是实在有点晚。后端

  • 引入 Fragment 后 Android 应用的生命周期 过于恐怖,因此尽管 Google 提倡使用 Fragment,但仍是能少用就尽可能少用。

  • 使用 Timber + Hugo 记录 Log 信息而不是使用原生的 Log 工具,这样无需再本身拼接类名,方法名,参数名和参数值,也不用为了使 Log 更容易被识别加上一堆 =========afafaf============= 或者 ~~~~~~~~~~~~~~~~~~~~~ 这样的提示符。

  • 使用 Android DataBinding,尽管你不必定喜欢它的数据绑定方式。可是使用了 DataBinding 后你无需调用 findViewById 后再强制进行类型转换,也不用使用 Butter Knife 之类的库编写各类注解。

  • 对于图像加载注重质量和包大小可使用 Picasso,注重加载速度或者须要支持 GIF 类型和大图片可使用 Google 人出品的 Glide。除此以外还有老牌的 Universal Image Loader 和相对较新的 Facebook 出品的 Fresco(Fresco 在这里面是重量级选手,不管是功能仍是体积,刚推出时坑很多,还有很是严重的内存泄露,目前该库已经做为 React Native 的图片加载库,不知道这些问题都解决了么)

  • 使用 IDEA Live Template 保存经常使用的类或方法的模板,这是我最常使用的方式,这样有时甚至能够减小近一半的工做量。

  • 强制竖屏,Android 上除了视频播放和游戏大部分状况下竖屏足以,根据 2-8 法则不少时候专门适配横屏是很大的资源浪费

从语言自己来讲

以上的方法在实现低碳环保的功能上仍是很是有限的,因此还有种方法就是直接从最根本的语言层面进行着手。

使用 Lambda 表达式

使用 Lambda 表达式能够省去很多代码,惋惜直到 Java 8 才支持,索性的是 Android 上有一些解决方法。

使用 Retrolambda Gradle Plugin

Retrolambda Gradle 插件能够在编译时经过字节码转换使 Android 可以使用 Lambda 表达式。

开启 Jack 与 Jill

在介绍 Jack 与 Jill 以前先来看看 Android 那坑爹的构建系统,如下图片来自 Google 官方文档,请注意这只是一个大纲,并且有些过期,实际更复杂,想一想若是没有 IDE 本身手动敲的痛苦吧:

A Detailed Look at the Build Process

而 Jack 与 Jill 就是在 Android M 时 Google 为了简化以上流程而推出的构建工具。

之前的主要流程

为了减少 I/O 读取的次数,dx 工具将全部 .class 文件合并成 .dex 文件

javac (.java --> .class) --> dx (.class --> .dex)

使用 Jack 与 Jill

Jill 将第三方 .class 文件和 .jar 文件转换为 .jayce 文件。
Jack 将 .java.jayce 文件合并后转换为优化过的 .dex 文件。

Jack (.java --> .jack --> .dex)
Jill (.class --> .jayce)

固然 Jack 实际是一个工具链,除了以上功能 Jack 还包含了 multidex, proguard 等大量功能,直接替代了原来构建过程当中的不少工具。

使用 Jack 与 Jill 还有一个吸引人的特色是能够在今年将发布的 Android N 平台使用上大部分 Java 8 的功能。感兴趣的人能够如今就去尝试一下,可是须要注意的是 IDE 必须大于 Android Studio 2.1 (preview),SDK 平台必须为 Android N Preview SDK。

此外因为 Java 8 提供的 Lambda 表达式实际就是经过函数式接口实现的,因此在使用 Jack 与 Jill 后这一功能也能够直接使用在 Android N 之前的平台,而不用使用 Retrolambda 这些第三方工具(固然其它的 Java 8 功能都不支持)

目前来讲 Jack 与 Jill 有一个很大的缺点就是速度较慢,不支持 Instant Run。此外因为不生成中间状态的字节码文件,因此开启 Jack 与 Jill 后基于字节码的各类工具(如 JaCoCo, Mockito)都将没法使用。(注:Gradle 插件在 1.5 版本提供了 Transform API,可让咱们直接对生成的 dex 文件进行处理,可是目前 Jack 与 Jill 不支持,因此使用该种方式 JaCoCo 仍然没法使用)

换种语言

相比较 Lambda 表达式也许换种语言是种更有效的方法。如下就介绍一下适用于 Android 开发的其它语言,固然这并非说真的须要在实际工做中应用。更多得是由于若是你只会用锤子,那你眼里的全部东西都是钉子,换种语言是为了开拓思路,了解在其它语言中是如何实现一样的功能的。

Java + Native

该方案以 Java 代码为主,以少许 Native 代码为辅。主要有两种实现方式:

Java + C/C++

很明显这种方法很是不环保,基于 NDK 的开发很是复杂,出了错误也很差调试,目前这种方式主要用于 Cocos2D-X 这种游戏引擎。

Java + Go

Go 从 1.5 版本开始同时支持 Android 和 iOS 开发。因为 Go 是 Google 亲儿子因此 1.5 出来时你们对将来都很是期待。不过至今为止实际发展很是缓慢,文档很是稀少。相比较使用 C/C++ 方式使用 Go 有这么几个特色:

优势:

  • 语法简单,开发迅速,不用写头文件,不用写 Makefile,不用手动写 Native 方法,借助插件 Go 代码会被直接编译成包含 .so 文件的 .aar 库,导入 Android 工程后就像写原生 Java 代码同样直接使用便可。

缺点:

  • 文档奇缺,发展缓慢剧。

  • 目前只支持 arm 架构。

  • 有 Bug,我写的代码编译版本选择 API 22 正常运行,选择 API 23 上直接奔溃。

Native + Java

该方案以 Native 代码为主,以少许 Java 代码为辅。最大的特色就是提倡以同一种语言为不一样平台编写不一样代码,而不是一套代码处处运行。主要表明有如下几种:

RubyMotion

RubyMotion 由 MacRuby 的开发者发明,能够经过 Ruby 代码编写 iOS 和 Android 代码。

优势:

  • 提供了 Android 上的几乎全部的 API 的 Ruby 实现,也能够直接使用 Java 库。

缺点:

  • iOS 还有些文档,Android 方面则没有任何像样的官方文档。致使我在写的时候须要打开 IDEA 先用 Java 写一遍大体框架而后再用 Ruby 进行改写。

  • 不支持直接调用 Java 代码,必须使用打包好后的 Java 库。

  • 除了官方发布的包,不支持其它任何 Gem 上的包。

  • 因为没有钱付正式版,因此我使用的是试用版,使用时不但难以调试,速度慢,并且还 Bug 满天飞,彻底没有写 Ruby 的爽快感,正式版估计会好点。

ReactNative

ReactNative 由 Facebook 在去年发布,一经发布瞬间成为 Github 上的网红。可使用 JavaScript 进行代码的编写以及动态更新是其最大特色。然而相比较 iOS 来讲 Android 版本并无发布多少时间,目前还有很多问题。因为最近在看 ReactNative 因此这里写得稍微详细点:

优势:

  • 使用 JavaScript 编写,ES 6 语法对于 Java 程序员可能更有亲和力。

  • Flex 布局和 JSX 语法和 Android 原生布局方式很是相近,不少属性几乎就是换个名字,容易上手。

  • 支持 HotLoad,写个界面刷一下就好了,Android 开发者终于不用忍受 Gradle 那漫长的编译过程。

缺点:

  • 目前只是 0.2x 版本,不稳定,而且 React Native 自己使用了很多已经标示为废弃的 API, API 有很大可能会大更新。

  • 若是碰到框架自己 Bug,基本没有修复的可能性,只能被动等待官方出解决方案或者切换为 Java 平台。

  • 原生 Android 开发就有各类兼容性问题,特别是对于国内小米,华为,魅族等平台,国外的 React Native 是否能处理得好不得而知。

  • ReactNative 框架自身绑定了很多第三方库,虽然这些库都挺有名的,但也不能保证人人喜欢,人人用获得。

  • 没有重用机制,致使 ListView 效率问题。

  • 没有布局管理器,组件间嵌套严重,实际代码中会有大量 <View> 嵌套 <View> 的状况,不适合写复杂的布局。

  • Android 有多种类型 Resource 文件,还有 10 多种限定修饰符,React Native 基本都没法使用,意味着在面对屏幕适配,i18n,切换主题等问题时会很是蛋疼。

  • 目前只支持老式的 Drawable 目录下的图片资源,不支持 5.0 之后的 Mipmap 目录下的资源。

  • Flux 和在其基础上的 Redux 架构与 Android 传统开发理念不符,很难吸引到广大码农。

其它 JVM 语言

相比较以上方案,使用其它 JVM 语言的最大特色就是能够和 Java 进行无缝切换,开发方式上没有什么变动,很容易让人接受。

Groovy

Groovy 官方从 2.4 开始就支持了 Android 开发。Groovy 自己是动态语言,效率较低。可是能够经过开启静态编译来提升效率。因为 Groovy 在处理 XML 方面是一绝,因此若是你的应用服务器是基于 SOAP 的话,那么使用 Groovy 替换 Java 无疑是更好的选择,原生的 DOM,SAX,PULL 方式使用起来都太痛苦了。

替换成 Groovy 后最大的优势就是上手没有任何什么难度, 毕竟全部 Android 开发者都写过 Groovy (build.gradle 实际就是 Groovy 源文件),而缺点就是编译速度会更慢。

Scala

Android 应用中经常须要将上下文传来传去,因此不少人都会在每一个 Activity 写上 mContext = this 这样没养分的代码。而使用了 Scala 后借助隐式参数 + 隐式转换 + 隐式类这三兄弟就不用写这些没有养分的代码。除此以外借助 Scala 各类 FP 特性代码量也能够获得大量减小。

可是替换成 Scala 后有一个致命的弱点就是主流的 Scala 的 2.11.x 版本核心方法多达 5w。这意味着加上 Android 的原生代码,即便你一行代码没写,仅仅是集成 Scala 运行环境后就超过了 65536 的限制。即便开启了 proguard 删除掉那些不用的代码这个问题也没办法根本解决,因此或许将 Scala 搬到 Android 平台并非一个好的解决方案。

Kotlin

Kotlin 是 JetBrain 研发的一门运行在 JVM 上的语言,官方支持 Android 开发,语法和其以后发布的 Swift 很是类似,因此也有人开发出了 Kotlin 2Swift 的工具,详细对比能够见Swift is like Kotlin。Kotlin 的语法能够看作是 Scala++--,其语法借鉴了 Scala,可是也去除了 Scala 中大量复杂的概念。

在全部 JVM 语言中,目前我的最推荐使用 Kotlin 进行 Android 开发。有如下几个缘由:

  • Kotlin 由 JetBrain 开发,因此对 Android Studio 有很好的支持。

  • Android 界举足轻重的 Jake Wharton 大神和其所在的公司 Square 都很欣赏 Kotlin,将一些 Android 库改写为了 Kotlin 版本。

  • Google Android 项目组也对 Kotlin 感兴趣,目前咱们常使用的 Databinding 的编译器就是 Kotlin 写的。

  • Kotlin 的运行库只有不到 7000 个方法,这意味着它比 v4 还要小。

  • Google 目前和 Oracle 的官司越演越烈,之前有传言 Google 会使用 Go 做为 Android 的一类语言,可是目前从发展速度来看可能性很小。近日又有传言 Google 会使用 Swift 来代替 Java,我的以为相比较而言不如说 Kotlin 可能性更大。(补:写完这段不久后 Swift 就仓库就出现了 For Android 的 Pull Request,看了下这玩意是基于 JNI 的,属于上面说的 Java + Native 的开发方式,对于编写应用来讲用处不大,不过相信会被很多人炒做一段时间)

  • Kotlin 学习 Clojure 也分为 Kotlin on JVM 和 Kotlin on JavaScript 两个版本。其中 Kotlin on JavaScript 目前内置了 JQuery,可是自己功能很弱,只能写些原始的 JS 代码。若是发展起来的话,说不定未来能够用于编写 ReactNative 代码。

  • Kotlin 没有什么历史负担,增长新特性时无需像 Java 同样思考再三。如下为 Kotlin 目前的 RoadMap,能够看到诸如协程之类的功能 Kotlin 都会在语言层面实现,而不用像 Java 同样必须依赖 Quasar 这种第三方库在字节码方面作文章才行。若是等 Java 实现的话搞很差须要等到 Java 20.

Kotlin RoadMap

就我我的开发中常使用的 Kotlin 功能有这么几种:

  • 方法扩展,该功能能够给已存在的类添加方法,本质上其实现相似 Scala 中的隐式类。因此你能够直接给 Activity 添加 toast, alert 功能。

  • 使用 DSL 语句来编写界面

  • internal 访问权限。咱们知道 Java 中包与包是没有任何关系的,这意味这 a.b 和 a.b.c 实际是两个包。因此在分层时 a.b.c 中不得不暴露大量的 public 方法给 a.b 包中所在的类。而在 SDK 开发中为了有良好的封装性,尽可能暴露更少的接口,因此每每不得不将大部分类都放在同一个包中,而后经过 default 访问权限来限制外部访问。类少的时候还可以忍受,类的一多的话就会很是混乱。Kotlin 中的 internal 访问权限能够限制只能属于同一个模块中的类进行访问,其它模块没法访问。那么什么是模块?在 Kotlin 中就是一个 jar 包,因此这功能对 SDK 来讲就是神器。

  • Kotlin Android Extension。使用后无需修改任何代码,直接就能够在代码中使用 Xml 中声明的任何的控件。

最后附上一段简单的 kotlin 代码

relativeLayout {
    textView {
        id = android.R.id.text1
        text = "Loading..."
    }.lparams {
        centerInParent()
    }
    editText {
        id = android.R.id.edit
        hint = "Page Count for retain"
        inputType = InputType.TYPE_NUMBER_VARIATION_NORMAL
    }.lparams {
        below(android.R.id.text1)
        centerInParent()
    }
    button("click") {

    }.lparams {
        below(android.R.id.edit)
        centerInParent()
    }.onClick {
        println("hello world")
    }
}.style {
    when(it){
        is TextView -> it.textSize = 20f
    }
}

以上 Go 和 Ruby 编写 Android 应用的示例能够见 AndroidDemoInOtherLanguages。其它 JVM 语言编写 Android 应用的示例能够见 AndroidDemoIn4Languages

扯了这么多可能有不少人以为就这些怎么可能实现低碳环保的编程。没错,你想的很对,要实现低碳环保的编程方式说到底只有惟一一个有效的方法就是说服你的项目经理或者其余有话语权的人取消或修改掉那些不环保的须要,仅此而已。本次扯淡到此为止。

做者信息:徐鸿福,多年后端及移动端开发经验,现任 MaxLeap UX 团队成员,主要从事于 Android 相关开发,目前对 Kotlin 和 Ruby 有浓厚兴趣。
原文博客连接:https://blog.maxleap.cn/archives/592

欢迎关注微信订阅号(发布技术文专用):从移动到云端欢迎加入咱们的MaxLeap活动群:555973817,咱们将不按期作技术分享活动。

相关文章
相关标签/搜索