开发 Android 应用程序的技巧:我的经验教训
已发表: 2022-03-11你好! 我是 Ivan,我从事 Android 应用程序开发已经有一段时间了。 或者看起来是这样。 回到过去(我们谈论的是 2009 年),Android 还只是个婴儿,我看着小绿人从那时起成长。 恐怕前段时间,Android 已经超越了我。
如今,Android 不仅在数以万计的不同手机和平板电脑上运行。 它就在你的手腕上,在你的客厅里,在你的车里,一旦我们开始为无生命的物体分配 IP 地址,它就会无处不在。 即使是经验丰富的 Android 开发人员也有很多基础!
此外,仅在 Google Play 上就有超过 100 万个应用程序,不包括 Amazon AppStore 或我们通常不感兴趣的市场,例如中国。 让我们不要忘记每年创造数十亿收入的无数移动应用程序开发公司。
那么,独立开发者如何才能在这个拥有大玩家的巨大市场中创造出成功的应用程序呢? 我不知道,我还没有制作成功的应用程序! 但是,我做了一个可爱的,我想和你分享我的故事。
第 1 课:连接点
成功(通常)不会在一夜之间发生,这不是我的第一个应用程序。 我有过一些意想不到的周末开发热潮,比如Macedonian Orthodox Calendar ,拥有超过 30,000 名用户,使用的语言不超过 400 万人可以理解,还有更成功的失败,比如TweetsPie ,一个拥有大量媒体报道的应用程序和一个糟糕的用户群只有 600 多个活跃用户。 那里有很多课!
虽然这些应用程序帮助我更好地理解了“被称为用户的难以捉摸的生物”的想法,但激发我灵感的是一个两个小时的项目。 最初是为了让我成为百万富翁而开发的,一旦有 1,428,571 名用户购买了该应用程序,因为谷歌从每一美元中抽取 30 美分, Dollar App就是用来测试我的商家帐户的。
我几乎不知道几年后我会收到一封来自一位快乐妈妈的电子邮件,说这是她花过的最好的一美元,因为每次我的应用程序拥抱她的男孩时,她都会微笑。
一个想法就是这样诞生的! 为什么不利用人类对拥抱的基本需求,让它变得漂亮呢? 使其适合特定的受众,具有互动性、挑战性、使用乐趣,甚至分享更有趣。
第 2 课:了解 Android 市场
我上面提到的所有东西加起来就是一个动态壁纸应用程序。 基础知识并不难猜。 Android 的市场份额比 iOS 更大,但 iOS 用户购买更多。 消息应用程序广受欢迎,但免费增值游戏收入最高。 中国、印度、巴西和俄罗斯是新兴市场,但缺乏消费习惯。 您可以阅读 App Annie 指数以获得更多见解。
那么动态壁纸应用程序如何适应这一点呢? 首先,它消除了大多数平台,因为动态壁纸是 Android 的东西。 其次,这个功能是在 Android 2.1 中添加的,所以它有一个很大的社区和很多漂亮的例子。 最值得注意的是 Paperland 和 Roman Nurik 的开源 Muzei,它可能是 Android 开发的最佳参考点。
虽然那里有很多动态壁纸,但其中大多数属于风景/天气类别,很少有属于可爱超载类别。 这是我们想要改变的东西,并提供一些让您每次解锁手机时都会微笑的东西,即使您出于完全不同的原因解锁它。 我们给了你一个可爱的小快乐,让你在晚上睡觉前或早上关掉闹钟时拥抱你。 甚至更好的是,使其个性化和可定制。
事不宜迟,在我们进入技术细节之前,我自豪地向您介绍:Ooshies - 动态壁纸
它的特点:
- 免费的动态壁纸应用程序,给你拥抱
- 12 种独特的 ooshies 可供选择
- 免费、不可锁定和可购买的内容
- 当前天气更新
- 社交登录和数据同步
- 季节性问候
- 很多惊喜
- 忍者猫
- 我们提到了拥抱吗?
第 3 课:尝试实现它
Ooshies 似乎是一个非常简单的 Android 应用程序创意。 画一个背景,覆盖一些云彩和星星,在上面放一只带气球的熊,你就可以开始了。 但不,这是安卓! 看似简单的事情往往非常困难,我们倾向于一遍又一遍地重复同样的常见错误。 以下是我面临的挑战的简要介绍:
硬件加速 - 为什么在 GPU 更胜一筹的情况下使用 CPU 进行绘图? 好吧,事实证明,在画布上绘制位图无法进行硬件加速。 至少暂时不会。
OpenGL - 如果我们想要硬件加速,我们需要使用 OpenGL ES 或者更好的框架来为我们完成大部分工作。
位图加载 - 众所周知的内存消耗问题。 我们需要为#ARGB 中的每个通道分配 1 字节 [0-255] 的内存,以显示单个像素。 此外,我们使用的图像通常具有比设备显示屏更高的分辨率。 将它们全部加载会很快导致 OutOfMemroyException。
家庭启动器 - 动态壁纸将托管在家庭启动器进程中,并且不同的启动器倾向于对动态壁纸服务(最值得注意的是 Nova 和 TouchWiz)给予不同的回调。
电池寿命 - 如果操作不当,动态壁纸和小部件会消耗大量电池电量。 随着关于棒棒糖(Android 5.0)可怕的电池寿命的所有嗡嗡声,第一个应用程序将是动态壁纸。
因此,覆盖位图,在画布上绘制,然后在触摸时切换帧以给予拥抱,这似乎没什么大不了的,即使它是在 CPU 上完成的,对吧? 没错,这不是问题。 但是,谁想要静态动态壁纸? 它超越了目的。 壁纸应该响应您的触摸,它应该在您滚动主屏幕时移动,它应该执行随机的善举并让您感到快乐。
并且有一个 Android 开发技巧。 有一个术语称为视差效应,用于在二维空间中增加深度。 想象一下自己在开车。 离你近的房子比远处的山移动得更快。 通过在画布上以不同的速度移动对象可以达到相同的效果。 虽然它们都在同一个平面上,但你的大脑会认为移动速度更快的物体离你更近。 就像添加阴影一样,视差效果添加了 z 轴。
这就是所有地狱都崩溃的地方! 在大多数以不同速度移动 Ooshie、天气叠加层和背景的设备上,会产生显着的帧速率下降。 以下是单帧的绘制方式:
canvas.drawBitmap(background, 0 - offsetX / 4, 0, null); canvas.drawBitmap(weatherOverlay, 0 - offsetX / 2, 0, null); if (!validDoubleTap) { canvas.drawBitmap(ooshieNormal, positionX - offsetX, positionY, null); } else { canvas.drawBitmap(ooshieTapped, positionX - offsetX, positionY, null); }
offset
是用户滚动距离的百分比。 这是壁纸引擎提供的回调:
@Override public void onOffsetsChanged(float xOffset, float yOffset, float xOffsetStep, float yOffsetStep, int xPixelOffset, int yPixelOffset){ super.onOffsetsChanged(xOffset, yOffset, xOffsetStep, yOffsetStep, xPixelOffset, yPixelOffset); // athe current offset should be a fraction of the screen offset to achieve parallax if (!isPreview()) { float newXOffset = xOffset * 0.15f; wallpaperDrawHelper.setOffsetX(newXOffset); if (isVisible() && hasActiveSurface) { wallpaperDrawHelper.drawFrame(false); } } }
我必须注意,如果我知道如何使用 OpenGL,那么所有这些都是不必要的! 它在我的TODO列表中,因为任何比我们现在拥有的更复杂的东西都需要硬件加速。 但是,目前我必须更努力地工作,而不是更聪明地工作(我愿意接受评论中的建议)。 所以这就是我们所做的:

第 4 课:使用现有资源
作为minSdk=15
倡议的大力支持者,我们从一开始就淘汰了所有 2.x 设备。 保持向后兼容性的努力大于用户无法/不愿意升级手机的可能收入。 因此,在大多数情况下,如果需要,我们可以通过添加禁用视差的选项来获得流畅的体验。
另一个大优化是我们如何处理位图。 绘制两个位图而不是三个位图可以实现非常相似的视差效果:
Ooshie 叠加 - 修剪和仔细缩放的 Ooshie 位图(可装饰)
组合叠加 - 以 Ooshie 速度的一小部分移动的组合背景和天气位图
这个 Android 开发技巧可以节省内存并加快绘制时间,但会稍微降低视差效果。
滚动主屏幕时,会经常绘制帧(理想情况下每秒超过 30 次)。 当主屏幕不可见时(某些锁定屏幕、某些应用程序抽屉、打开/切换应用程序等),不要绘制它们以最大限度地减少 CPU 使用率,这一点至关重要。
这一切都与天气更新密切相关。 最初有一个重复的任务,每隔一两个小时执行一次,以同步天气,但这确实有点过头了。 如果用户看不到壁纸,则天气信息无关紧要。 所以现在,天气更新只有在壁纸可见时才会发生。
long lastUpdate = prefStore.getLong(SharedPrefStore.Pref.WEATHER_TIMESTAMP); if (System.currentTimeMillis() - lastUpdate > Consts.WEATHER_UPDATE_INTERVAL){ // update the weather if obsolete Intent intent = new Intent(getApplicationContext(), WeatherUpdateService.class); startService(intent); }
所以,基本上,这里是内存优化平滑软件位图绘图的清单:
- 合并位图一次
- 绘制更少的位图
- 仅按需重绘
- 避免后台任务
- 为用户提供对流程的一些控制
第 5 课:测试。 测试。 测试
我不能强调这是多么重要! 永远,我再说一遍,在测试之前发布您的应用程序! 而且,我并不是说您应该进行测试。 你编写了代码,你知道它是如何工作的,你通过了解期望来影响结果。 我不是在谈论 JUnit 测试(尽管推荐),而是关于分阶段推出,即 alpha 和 beta 测试。
如果您从事 Android 软件开发,这些术语很简单,但这里有一个简要说明:
Alpha 测试人员 - 由您的队友和业内人士组成的一小群人,最好是 Android 开发人员。 他们很有可能会使用高端设备,并且会与开发人员的选项一起玩。 他们会向您发送堆栈跟踪、错误报告,甚至为您提供一些代码/UI 优化提示和技巧。 非常适合具有部分/缺失功能的早期版本。
Beta 测试人员 - 具有各种人口统计数据的更广泛的受众。 稳定版本应该在这里发布。 即使您的忍者级别太高,您也永远无法预测,更不用说考虑所有可能的 Android 发行版以及人们使用手机的方式。
一旦我们通过了 alpha,我认为我们已经完成了。 但是,男孩我错了吗?! 事实证明,并非所有 Android 用户都拥有装有最新软件的 Nexus 设备! 谁会知道? :)
以下是基于此启示的一些 Android 开发问题:
不同的启动器有不同的默认主屏幕——通常是第一个或中间的主屏幕,据我所知,没有办法知道它的位置。
在不知道默认主屏幕位置的情况下很难将 Ooshie 居中 - 因此用于调整视差偏移的设置滑块。
普通用户不知道视差偏移是什么意思——应该在设置页面上使用更简单的术语。
随机用户会建议您的下一个功能。
因此,我要感谢我们所有的 beta 测试人员所做的辛勤工作。 我希望在其他人之前获得所有最新功能是对他们奉献精神的体面奖励。 如果您愿意,您也可以加入我们的 Google+ Beta 社区。
第 6 课:让数据说话
制作一个今天出类拔萃的 Android 应用程序比制作一个计算器应用程序要困难一些,当时在 2009 年还没有。制作完美的应用程序很难。 主要是因为完美是在旁观者的眼中。 对我有好处的,并不一定对你有好处。 这就是为什么让应用程序增长很重要的原因。 我们的新功能路线图清单表明,我们在整个 2015 年都有足够的工作量。除其他事项外,我们很快将包括:
- 声音
- 季节性背景
- 自定义(背景颜色、天气包、ooshie 皮肤等)
- 地区特定的ooshies(例如头巾)
- 许多新的ooshies和解锁它们的方法
现在,我们可能会一直将应用程序保持在测试阶段,直到一切都完成,但这样我们就丢弃了有价值的数据。 并非所有 Beta 版测试人员都会抽出一部分时间向您发送反馈。 这就是您可以受益于使用工具获取反馈的地方。 您可以使用 Google Analytics、Flurry、Mixpanel、Crashalytics、ACRA 等来收集使用数据。
例如,通过分析数据,我们注意到用户不会经常点击设置按钮,因此我们使其更加明显,并添加了调整设置的快速教程。
虽然这是一个后台进程,但它可以用来进一步改善用户体验。 为什么不向用户显示多少次:
- 他/她得到了一个拥抱
- 多少个雨天被一个微笑照亮
- 使用迷你游戏解锁 Ooshie 需要多少次点击
- 有多少朋友因为你安装了这个应用
这很重要,因为它为他们的行为提供了后果。 不要犯我们的教育系统所犯的同样错误,使用户成为被动的内容消费者。 让他们负责。 让他们可以选择控制自己的设备并创建自己的个人体验。 如果您设法将所有这些打包成一个可爱的捆绑包,在第一次飞溅时偷走微笑,那么要求用户提供垃圾邮件以解锁内容并不是太牵强。
最后,您需要以这些数据为指导来改进您的 Android 应用程序开发。 虽然主要是为妈妈/孩子设计的,但这个应用程序可能会在其他人群中流行起来。 它可能不符合我们最初的愿景,但必须满足用户的需求。 否则他们会找到可以的人。
结论
让我们回到我最成功的失败 TweetsPie。 尽管获得了一些奖项和大量的媒体报道,但该应用程序未能留住它的用户(原因超出了本文的范围)。
成功并不总是显而易见的。 由于整个经历,我学到了很多东西。 我至少在各种活动和黑客马拉松上就如何(不)作为一家初创公司失败进行了十几次讲座,并设法在 Toptal 获得了几个客户。
更重要的是,通过遵循本指南中的提示和技巧,我尽量不要在 Ooshies 上重复同样的 Android 开发错误。
总结这个长篇指南,我们定义为成功的是,在后期阶段,与我们一开始设定的目标紧密结合。 当然,最常见的成功衡量标准是赚很多钱。 无论您的应用程序是否成功,您都必须努力实现它,并相信我最终您会成为一个更好的人(希望能够设法学习 OpenGL)。 你会结交新朋友,很少有敌人,如果你足够幸运/足够聪明,你会让很多用户开心。
您可以查看我们的网站或下载 Ooshies 试一试。