写点什么

十六年全栈开发者的 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:132511

评论

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

OGA 联盟正式成立!禅道作为理事单位助力共建开源生态!

禅道项目管理

项目管理 DevOps gitlab

大数据好书推荐

五分钟学大数据

反洗钱监管再度升级,看这家金融集团如何应对

索信达控股

大数据 银行 金融监管 风险管理 数据管理

《原则》(三)

Changing Lin

系统性思维 系统之美2

张老蔫

28天写作

蓝海战略 - 如何设计与众不同的价值曲线

石云升

战略思考 职场经验 6月日更

defi流动性系统开发案例详情丨defi流动性源码功能

系统开发咨询1357O98O718

龙蜥专场精彩回放来了!10位技术大咖、242位开发者相聚

阿里云基础软件团队

持续测试 | 测试流程提效:在 CODING 中实践迭代内的持续测试

CODING DevOps

DevOps 测试计划 持续测试 迭代式测试

OpenYurt v0.4.0 新特性发布:高效地管理边缘存储资源

阿里巴巴云原生

云原生

Flink 在有赞的实践和应用

Apache Flink

flink

拍乐云推出业内首个「线上美术教学音视频方案」,打造极致互动体验

拍乐云Pano

新大陆!阿里P9整理出:Java架构师“成长笔记”共计23版块

Java架构师迁哥

分享:在阿里做Java开发的这五年,收获与感悟

Java架构师迁哥

拍乐云受邀QCon大会 | 详解音视频技术架构实践,首发美术教学音视频方案

拍乐云Pano

从零开始学习3D可视化之控制对象(2)

ThingJS数字孪生引擎

可视化 数据化 3D 3D可视化

defi流动性挖矿系统开发案例分析,defi流动性挖矿现成源码

系统开发咨询1357O98O718

如何设置HashMap初始化大小

Hex

后端 hashmap

研发自动化,你准备好了么?

PingCode研发中心

研发管理 研发效能 研发工具 研发团队

官宣!禅道与极狐(GitLab)达成深度合作,携手推进开源开放DevOps生态发展

禅道项目管理

项目管理 DevOps gitlab

联邦计算在百度观星盘的实践

百度Geek说

百度搜索与推荐引擎的云原生改造

百度开发者中心

云原生

defi流动性挖矿系统开发(案例版)丨defi流动性挖矿源码现成版

系统开发咨询1357O98O718

系统性思维 系统之美1

张老蔫

28天写作

23种设计模式,正确的解读方式原来是这样

Java架构师迁哥

阿里P8熬了一个月肝出这份32W字Java面试手册,在Github标星68K+

Java 程序员 面试

【干货篇】bilibili:基于 Flink 的机器学习工作流平台在 b 站的应用

Apache Flink

flink

python使用命令行传入参数

卤蛋翔

6月日更

2021金三银四面试经历:腾讯三面落马+拒网易、CVTE后,字节四面成功拿下offer

Java 程序员 架构 面试

你想进大厂吗?阿里Java面试“内幕”分享

Java架构师迁哥

百度开发者中心全新升级 | 文末六一送福利

百度开发者中心

百度 福利

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