前端未来的主流技术方向有哪些?腾讯、京东、同城旅行等大厂都是怎么布局的?戳此了解 了解详情
写点什么

十六年全栈开发者的 Android 开发踩坑实录

2021 年 3 月 31 日

十六年全栈开发者的Android开发踩坑实录

这是一个完完全全马后炮的故事。身为拥有差不多十六年开发经验的全栈 web 开发者,作者对构建 web 应用所需要的各种技术可谓是了如指掌。而在最近几年的工作项目中,作者第一次成为了一名安卓开发者。在经过一段时间的磨合之后,作者才意识到,从 web 开发转型到安卓、移动端应用开发,开发者的思维也需要一定转换。


安卓开发的萌新们走错的路大多数都可以在项目后期通过重构或修改构建流程解决,不断打磨直到单元测试完美覆盖需要的所有情况也能处理一些小错误。但剩下的漏网之鱼就不是那么好解决了,这些足以在 app 的生命历程中造成持久影响、令人想要将整个项目推翻重来的错误中,有些甚至让作者羞于启齿自己曾经犯过它们。以下将提供一些防止你想要穿越回过去重做项目导致时间悖论(笑)的小 tips,希望能够帮助大家预防那些难以摆脱的糟糕麻烦。

添加应用内更新


立刻、马上。一直到出炉一年后,我们才把更新通知功能塞进我们的 app 里。内置的更新提醒功能在项目初始就添加的话,那么过程就还算简单,但如果拖到后期才做的话,难免会造成不少的问题,其中包括:必须手动搭建自定义流程,以及用户自行尝试跳过更新。


// Creates instance of the manager.val appUpdateManager = AppUpdateManagerFactory.create(context)// Returns an intent object that you use to check for an update.val appUpdateInfoTask = appUpdateManager.appUpdateInfo// Checks that the platform will allow the specified type of update.appUpdateInfoTask.addOnSuccessListener { appUpdateInfo ->    if (appUpdateInfo.updateAvailability() == UpdateAvailability.UPDATE_AVAILABLE        // For a flexible update, use AppUpdateType.FLEXIBLE        && appUpdateInfo.isUpdateTypeAllowed(AppUpdateType.IMMEDIATE)    ) {        // Request the update.        appUpdateManager.startUpdateFlowForResult(        // Pass the intent that is returned by 'getAppUpdateInfo()'.        appUpdateInfo,        // Or 'AppUpdateType.FLEXIBLE' for flexible updates.        AppUpdateType.IMMEDIATE,        // The current activity making the update request.        this,        // Include a request code to later monitor this update request.        MY_REQUEST_CODE)        }}
复制代码


相信我,这项功能将会是你的 app 的突破式改变。app 的现有用户可能已经通过其他的 app 习惯了应用内更新功能,甚至会理所应当地认为这其实应该是移动端平台的一项特点之一。但实际上,直到我亲身经历了安卓开发,才知道原来这项功能还要开发者手动添加。当你的 app 不幸停止运行之后,用户并不会去找软件更新包,他们只会卸载再安装,甚至更糟的是,他们会在应用商城留下评论。

限制 API 密钥


先让程序跑起来,出了问题再去打补丁。或许你也有这个习惯,但请不要继续拖延了。指路一篇关于谷歌云平台上 API 密钥 的文章,但对于其他平台,这一点同样适用。


对于 GCP(谷歌云平台)来说,我们只需要在登录谷歌账号,选择要设置限制的 API 密钥后,系统便会跳转到密钥的属性界面。在“应用限制”里选择安卓应用,点击“+”添加软件包名称到需要添加限制的 API 密钥下即可。至于添加证书指纹,可以直接复制页面中的命令后,按照网页右侧的指示,只需要几分钟就可以完成。


我们在 app 出厂两年后才开始限制 API 密钥。然而在限制之后,app 的一个地图功能罢工了。回滚更改之后,我们费了好大一番功夫才找到问题所在。app 所使用的大部分谷歌官方软件包都可以完美适配限制 API 密钥后的代码,唯独其中一张地图需要重写另一套 API 调用代码。如果在项目初始我们能考虑到 API 密钥的限制问题,并将其写入源码,这无疑会增加开发时间,但到了后期我们就可以不用再担心限制的问题了。


故事并没有在这里结束。为了能在保证地图的正常运行并限制 API 密钥,我们不得不进行强制更新。我们有后台的统计数据可以监控用户的更新流程,而数据表明,有 90% 的用户在收到更新通知的几周后才进行更新,而另外 10% 的用户则在地图几乎彻底罢工的情况下依旧选择不更新,完全不晓得他们是怎么忍受这种 bug 的。

内部 API 版本控制


当我还在主攻 web 开发时,我一直都搞不太明白为什么有人会想这么做。在更新前端代码后,为什么还要留着旧版本的 API?怎么想都是无用的浪费。


但用户使用的软件版本不同时,API 的大更新可能会导致软件大范围的崩溃。应用内更新的方法可以帮忙缓解这种问题,但过程将会无比漫长。划分 API 版本更像是一种针对这类软件崩溃的,快捷简单的解决方案,而非是我曾经以为的过度工程。

万事先离线


我们的 app 是有实用目标的。当我们收到用户反馈的 app 反应卡顿、响应超时时,我还只是移动端应用开发的小白,刚刚接触到一个新的名词:优先离线(Offline First)。如果用户联网失败,所有未上传、未保存的东西都会丢失,等到连接恢复,他们将不得不重新输入所有的内容。


优先离线的结构会将更改内容写入本地数据库,等有网络连接时再进行同步。这样一来,用户得以在离线下使用 app,联网时响应也会更快,用户不用再干巴巴地等着服务器传回响应才能进行下一步操作。



离线优先的功能在项目后期可能会更难实现,难易度取决于 app 的数据的复杂程度。所以还请尽快决定 app 是否需要它。我们至今还在研究要如何在我们的“高龄”app 中更好地实现这项功能…

谨慎选择导航项


如果你的安卓 app 结构复杂、有很多界面的话,开发进程到后期再去修改导航项麻烦程度将超乎你的想象。我们的 app 在后期是直接改为了底部导航的形式。


在一些情境下,安卓开发中的 Activity 可以被看做是 app 中某块屏幕的代码;安卓 3.0 才有的 Fragments 则可以被理解子视图代码或是 app 中的部分代码。二者的 layout 都是通过 XML 定义的。


我们的导航指向的是 app 不同区域中的主要功能,这些导航小卡片又各自导向不同的子功能,一共连接起了三十余个 Activity。这些也不过是这款基于 Activity 的 app 中的四个 fragment。导航抽屉则是另一种常见导航形式,主要服务对象是 Activity 对接 Activity 形式的导航需求。


底部导航因为 app 的底边栏一直都是可见状态,所以它的设计对象是 fragment 式导航。在将底边栏添加到 Activity 后,接下来我们只需要它相关的代码敲进该 Activity,并把它的 view 添加到 Activity 的 layout 中。这样,通过点击底边栏的按钮,我们就可以把 fragment 加载到 Activity 中了。


所以,为了在 app 中添加底部导航栏,我试图将 Activity 转换为 fragment。结果很悲惨,过量的 bug 直接导致软件崩溃,浪费了我一个月的时间。如果我们只有五六个 Activity,那么解决起来可能还不算太难,但事实上我们的 app 足足有三十多个 Activity!


这直接导致了我在这一个月了放弃了其他工作,专注为每一个 Activity 添加导航功能。我还尝试过创建一个 helper 函数,但这并不能帮我省多少麻烦,到头来还是要一个个地为 Activity 写代码。同时,我还需要把底边栏添加到所有的 layout 中,并且在已有的 layout 中为这个小家伙腾地方。再加上还要对 Activity 栈进行编程操作,防止出现竞赛条件。虽然过程繁琐,但最后好歹还是成功了,并且效果还不错。只不过如果在项目最初我就能把底部导航栏加上去,并且从基于 fragment 的方向开始设计,那么将轻松很多。


这只是份不完全清单……


当然,在开始你的第一份安卓应用时,还有很多其他的事情需要考虑的,比如添加单元测试、确定一个 app 的模式后不要更改等等。但如果你之前有接触过其他类型的开发模式,这些应该都不陌生。或许你并不会遇到与文中提到的一模一样的问题,但恐怕不会相差太多。希望这些小 tip 能够帮你意识到安卓开发与其他的类型的开发是不甚相同的,这些开发决定的影响或许能持续相当长一段时间。


原文链接:


https://triplebyte.com/blog/everything-id-do-differently-if-i-could-go-back-and-rewrite-my-android-app-today

2021 年 3 月 31 日 15:131081

评论

发布
暂无评论
发现更多内容

作为一名Java程序员,技术栈的广度深度都不够还想要高薪?请先把这些技术掌握再说。

Java架构之路

Java 程序员 架构 面试 编程语言

LeetCode题解:50. Pow(x, n),暴力法,JavaScript,详细注释

Lee Chen

算法 LeetCode 前端进阶训练营

了解HashMap数据结构,超详细!

程序员的时光

面试 hashmap HashMap底层原理

开发一个交易所需要多少费用?币币交易系统

135深圳3055源中瑞8032

合约跟单软件开发,一键跟单系统搭建

135深圳3055源中瑞8032

惠普中国(HPE)技术总监教你如何做个“火影般”的“架构师”

Java架构师迁哥

Java 程序员 架构

政府和企业如何认识到区块链的好处

CECBC区块链专委会

比特币 区块链

大数据上手实战!训练营“9营齐开”第二季限时免费报名啦

Apache Flink

大数据

架构师训练营培训第一周总结

lakers

极客大学架构师训练营

阿里18道常见的MySQL面试题,含解析

Java架构师迁哥

区块链多币种钱包开发服务商,多币种钱包APP

135深圳3055源中瑞8032

2020,国产数据库崭露峥嵘的发轫之年

墨天轮

数据库 阿里云 华为云 SQL优化 活动专区

Java高并发编程的一本百科全书《Java高并发编程详解:多线程与架构设计》,把Java语言中最为晦涩的知识点都详解出来了!

Java架构之路

Java 程序员 架构 并发编程 编程语言

Spring 5.2.7和SpringBoot 2.3.3中文翻译发布啦!!!

青年IT男

spring springboot

我从高级开发者身上学到的19条编码原则

Java架构师迁哥

一周信创舆情观察(10.12~10.18)

统小信uos

架构师训练营第 1 期第五周总结

Leo乐

极客大学架构师训练营

架构师训练营第一期 - 第五周课后 - 作业二

极客大学架构师训练营

限量,字节技术官十年经验总结并发编程核心方法与框架,太强了

周老师

Java 编程 程序员 架构 面试

数字货币可能重构全球货币体系

CECBC区块链专委会

数字货币 金融

架构师训练营第一期 - 第周五课后 - 作业一

极客大学架构师训练营

笔记本中的“全优生”,英特尔Evo产品上市首日秒光!

新闻科技资讯

区块链技术本质再认知

CECBC区块链专委会

区块链 大数据

华为云如何赋能无人车飞驰?从这群AI热血少年谈起

华为云开发者社区

人工智能 无人驾驶

USDT承兑商支付系统开发,区块链跨境支付源码

135深圳3055源中瑞8032

1分钟带你入门 React SCU、memo、pureCom

Leo

react.js 前端 React 前端进阶训练营 前端性能优化

第一周学习总结

Griffenliu

架构师训练营 - 第一周学习总结

joshuamai

第五周学习代码技术选型总结

三板斧

极客大学架构师训练营

知识视频创作者何去何从,百度给出解答

脑极体

化身“监工”的AI,我们该如何相处?

脑极体

技术为帆,纵横四海- Lazada技术东南亚探索和成长之旅

技术为帆,纵横四海- Lazada技术东南亚探索和成长之旅

十六年全栈开发者的Android开发踩坑实录-InfoQ