写点什么

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

  • 2021-03-31
  • 本文字数:3234 字

    阅读完需:约 11 分钟

十六年全栈开发者的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-03-31 15:132649

评论

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

2023 年龙蜥社区最佳合作伙伴出炉,统信软件、中兴通讯、浪潮信息等 17 家厂商上榜

OpenAnolis小助手

龙蜥社区

龙蜥社区荣获 OSCHINA “2023 年度优秀开源技术团队”

OpenAnolis小助手

操作系统 国产操作系统 龙蜥社区

中兴通讯携手龙蜥社区,共创繁荣生态 | 2023龙蜥操作系统大会

OpenAnolis小助手

操作系统 国产操作系统 龙蜥社区 中兴通讯

一文读懂Partisia区块链的MOCCA 方案:让资产管理可信且可编程

加密眼界

释放硬件潜能,激活软件生态 《龙蜥+超级探访》第二期走进 Intel

OpenAnolis小助手

操作系统 国产操作系统 英特尔 龙蜥社区 龙蜥+超级探访

2023年度优秀贡献者名单正式公布!恭喜 36 个团队/个人、30+企业上榜

OpenAnolis小助手

龙蜥社区

LC串联谐振拓扑仿真建模

芯动大师

控制 电源 LC电路

开始报名,赢取丰厚奖金!2024 大学生操作系统赛—龙蜥赛题等你来挑战

OpenAnolis小助手

龙蜥赛题

2023年回顾| 龙蜥这一年:群擎并举,众芯共魂

OpenAnolis小助手

操作系统 国产操作系统 龙蜥社区

PMO 总监干货分享:Jira Cloud 驱动项目管理创新

跟YY哥学Jira

项目管理 Jira Cloud PMO 协作

【专访英特尔】软硬结合,共赴服务器操作系统的云智未来

OpenAnolis小助手

AI 操作系统 国产操作系统 intel 龙蜥社区

金智维的务实主义,打响大模型落地“突围战”

脑极体

AI

根基已筑!Anolis OS 23.1 预览版本搭载 Linux 6.6 内核和工具链升级完成

OpenAnolis小助手

操作系统 国产操作系统 龙蜥社区 龙蜥产品发布 Anolis OS

Sora小白教程一文通,如何使用Sora?

蓉蓉

openai sora

创新奋进,共筑国产基础软硬件的美好未来 | 2023 龙蜥操作系统大会

OpenAnolis小助手

操作系统 国产操作系统 龙蜥社区 龙芯中科

群擎并举,众芯共魂,龙蜥重磅首发下一代操作系统“1+3”能力模型

OpenAnolis小助手

操作系统 国产操作系统 龙蜥社区 2023龙蜥操作系统大会

联合阿里云,首批诚邀 30 家!Alibaba Cloud Linux 伙伴招募计划发布

OpenAnolis小助手

操作系统 国产操作系统 龙蜥社区 Alibaba Cloud Linux

重构大面积if-else代码

廊虞

Java 设计模式 策略模式

院士专家任高级顾问,龙蜥生态日见成熟

OpenAnolis小助手

操作系统 国产操作系统 龙蜥社区

龙蜥社区正式推出驱动基线 V1.0,打造更加稳定、高效的生态系统

OpenAnolis小助手

操作系统 国产操作系统 龙蜥社区

C++ 编程入门指南:深入了解 C++ 语言及其应用领域

小万哥

程序人生 编程语言 软件工程 C/C++ 后端开发

【专访浪潮信息】构建开放公平的社区生态,中国服务器操作系统崛起进行时

OpenAnolis小助手

操作系统 国产操作系统 龙蜥社区 浪潮信息 2023龙蜥操作系统大会

15 万奖金!开放原子开源大赛 OpenAnolis -云原生赛题报名开始

OpenAnolis小助手

操作系统 国产操作系统 龙蜥社区 龙蜥赛题

Intel 技术总监:同心共行,共建龙蜥 | 2023 龙蜥操作系统大会

OpenAnolis小助手

操作系统 国产操作系统 intel 龙蜥社区 2023龙蜥操作系统大会

【专访阿里云】云智融合转型期,国产服务器操作系统路在何方?

OpenAnolis小助手

阿里云 操作系统 国产操作系统 龙蜥社区

[每日秒懂] 持续交付2.0

dinstone

持续交付 双环模型 科学探索-快速验证

Anolis OS 获 Gitee 最有价值开源项目称号

OpenAnolis小助手

操作系统 国产操作系统 龙蜥社区

十六年全栈开发者的Android开发踩坑实录_语言 & 开发_Stephan Miller_InfoQ精选文章