1. 从零到上线:为什么我选择 WorkBuddy 作为主力开发工具
去年年底我接了一个私活,客户要求三个月内交付一个能上架安卓应用市场的工具类 App。团队就两个人,一个后端一个客户端,预算不算宽裕,时间也紧。当时摆在面前的选择无非是原生开发、跨端框架、或者用低代码平台快速搭。原生开发周期太长,跨端框架学习成本不低,最后我把目光落在了 WorkBuddy 上。
WorkBuddy 这个工具,简单说就是一个面向移动端应用快速搭建的开发工作台。它把常见的页面结构、数据绑定、网络请求、本地存储这些模块做了封装,同时保留了足够的扩展能力,让你可以在它的基础上写自定义逻辑。对于中小型项目来说,它能把你从重复的脚手架搭建中解放出来,把精力集中在业务逻辑和用户体验上。我这次要做的 App 核心功能包括任务清单管理、本地数据持久化、简单的数据统计图表、以及一个内嵌的 WebView 页面用来展示帮助文档和用户协议。
适合谁来参考这份经验?如果你是有一定 Java 或安卓基础、想快速把想法变成可上线产品的开发者,或者你是一个小团队的技术负责人,需要在有限时间内交付一个稳定可用的 App,那这篇内容应该能帮你少走不少弯路。我会把整个项目拆成六个阶段来讲,每个阶段里踩过的坑、做过的取舍、以及最后验证有效的方案,都会毫无保留地写出来。
整个项目从立项到上架,前后大概用了十周时间,其中开发占了六周,测试和修 bug 占了两周,剩下两周是应用市场审核和素材准备。这个节奏不算快,但考虑到只有一个人写客户端,我觉得已经压得比较紧了。下面我按阶段来展开,每个阶段都会说清楚我做了什么、为什么这么做、以及遇到了什么问题。
2. 第一阶段:环境搭建与项目初始化
2.1 开发环境的选择与配置
WorkBuddy 的运行依赖 Java 环境,所以第一步就是把 JDK 装好。我用的是 JDK 17,这个版本在稳定性和新特性之间平衡得比较好。安装完之后记得配置JAVA_HOME环境变量,不然 WorkBuddy 启动时会报找不到 Java 运行时的错误。这个坑很基础,但我确实见过有朋友卡在这里半天。
安卓开发环境方面,Android Studio 是绕不开的。我用的版本是 Hedgehog 2023.1.1,搭配 AGP 8.1。这里有个细节需要注意:WorkBuddy 对 Android Studio 的版本有一定要求,太老的版本可能不兼容它生成的工程结构。我建议至少用 Arctic Fox 之后的版本。安装 Android Studio 的时候,SDK 的选择也有讲究。我勾选了 Android 8.0(API 26)到 Android 14(API 34)这几个版本,因为 WorkBuddy 默认生成的工程minSdkVersion是 26,targetSdkVersion是 34。如果你的目标用户群体里有大量老设备,可以把minSdkVersion降到 23,但要注意部分 API 的兼容性处理。
注意:安装完 Android Studio 后,务必在 SDK Manager 里把 Android SDK Build-Tools、Android SDK Platform-Tools、以及对应 API 级别的 SDK Platform 都勾上。我一开始只装了 Platform,结果构建时报缺少 Build-Tools,又回头补装了一次。
2.2 WorkBuddy 项目初始化与目录结构
WorkBuddy 创建项目的方式有两种:一种是通过命令行工具workbuddy init生成基础工程,另一种是在 IDE 里通过图形界面新建。我两种都试过,命令行方式更适合自动化脚本,图形界面方式对新手更友好。我最后用的是命令行方式,因为可以自定义包名和项目路径。
初始化完成后,工程目录结构大致是这样的:app模块下分src/main/java放 Java 代码,src/main/res放资源文件,src/main/assets放静态资源。WorkBuddy 额外生成了一个workbuddy目录,里面存放它的配置文件,比如workbuddy.config.json,这个文件里定义了页面路由、数据源绑定、以及一些全局配置。我建议在项目初期就把这个文件的结构理清楚,不然后面页面多了容易乱。
包名我用了com.example.taskbuddy,这个包名在上架时是可以改的,但改起来比较麻烦,所以最好一开始就定好。项目名称和包名一旦确定,后续所有代码引用都会基于它,中途修改会导致大量文件需要同步调整。
2.3 依赖管理与版本控制
WorkBuddy 生成的工程默认使用 Gradle 作为构建工具。build.gradle文件里已经预置了一些常用依赖,比如网络请求库、JSON 解析库、图片加载库。我额外加了两个依赖:一个是MPAndroidChart,用来画统计图表;另一个是AndroidX WebKit,用来处理 WebView 的兼容性问题。
版本控制我用的是 Git,配合.gitignore文件忽略build目录、.idea目录、以及本地配置文件。这里有个经验:WorkBuddy 的配置文件里可能包含一些本地路径信息,这些不应该提交到仓库。我在.gitignore里加了workbuddy/local.properties这一条,避免把本机路径带到团队其他成员的机器上。
实操心得:初始化完成后,先跑一次
./gradlew assembleDebug,确认基础工程能正常构建。这一步能帮你提前发现环境问题,而不是等到写了几百行代码之后才发现构建失败。
3. 第二阶段:核心功能设计与页面搭建
3.1 页面路由与导航结构设计
WorkBuddy 的页面路由机制是基于配置文件的。你在workbuddy.config.json里定义好每个页面的路径、对应的 Java 类、以及页面之间的跳转关系,它就会自动生成导航代码。这种方式的好处是页面关系一目了然,改起来也方便。但缺点是灵活性不如手写 Intent 跳转,特别是涉及到带参数跳转和返回结果处理的时候。
我的 App 一共有五个主要页面:任务列表页、任务编辑页、统计页、设置页、以及帮助文档页。任务列表页是入口,底部有一个导航栏可以切换到统计页和设置页。任务编辑页是从列表页跳转过去的,帮助文档页是从设置页跳转过去的。这种结构比较简单,用 WorkBuddy 的路由配置完全能覆盖。
对于带参数的跳转,比如从列表页点击某个任务进入编辑页,WorkBuddy 支持在路由配置里定义参数名和类型。我在配置里定义了taskId这个参数,类型是long。跳转的时候通过WorkBuddy.navigate("task_edit", bundle)传递参数,编辑页在onCreate里通过getIntent().getExtras()取出来。这套流程跑通之后,后面加新页面就很快了。
3.2 数据模型与本地存储方案
任务清单这个功能,核心数据模型就是任务对象。我定义了一个Task类,包含id、title、description、dueDate、priority、isCompleted这几个字段。id用自增长整型,dueDate用时间戳存储,priority用枚举值表示高、中、低三档。
本地存储我选了 Room 数据库。Room 是 Android 官方推荐的 ORM 框架,在 SQLite 基础上做了一层封装,用起来比直接写 SQL 方便很多。WorkBuddy 默认没有集成 Room,需要自己加依赖。我在build.gradle里加了androidx.room:room-runtime和androidx.room:room-compiler,然后用注解定义了Task实体和TaskDao接口。
这里有个坑要注意:Room 的实体类字段名和数据库列名默认是一致的,如果你想起不同的列名,需要用@ColumnInfo注解指定。我一开始没注意,结果数据库里的列名和代码里的字段名对不上,查询的时候一直返回空。后来加了@ColumnInfo(name = "due_date")这样的注解才解决。
注意:Room 的数据库操作不能在主线程执行,否则会抛
IllegalStateException。我一开始图省事直接在onCreate里查数据库,结果 App 一启动就崩。后来改成用AsyncTask或者ExecutorService在后台线程查,查完再回调到主线程更新 UI。
3.3 列表页与编辑页的交互实现
任务列表页用的是RecyclerView,配合ListAdapter和DiffUtil做数据更新。DiffUtil的好处是只刷新变化的那部分 item,而不是整个列表重绘,性能提升很明显。我一开始用的是notifyDataSetChanged(),列表一长就卡顿,换成DiffUtil之后流畅多了。
编辑页的布局用了ConstraintLayout,这个布局管理器比LinearLayout和RelativeLayout更灵活,能减少布局嵌套层级。WorkBuddy 生成的默认布局就是ConstraintLayout,我直接在这个基础上改的。编辑页里有文本输入框、日期选择器、优先级单选按钮、以及保存和取消按钮。日期选择器用的是DatePickerDialog,优先级用RadioGroup包三个RadioButton。
保存逻辑是这样的:点击保存按钮后,先做表单校验,标题不能为空,日期不能早于今天。校验通过后,把数据封装成Task对象,如果是新建就调insert,如果是编辑就调update。操作完成后调finish()关闭当前页面,回到列表页。列表页在onResume里重新查询数据库,保证数据是最新的。
4. 第三阶段:WebView 集成与混合开发
4.1 WebView 的初始化与配置
帮助文档页我用了 WebView 来加载本地 HTML 文件。这样做的好处是文档内容可以用 HTML 写,排版灵活,改起来也不用重新编译 App。WorkBuddy 对 WebView 的支持还算友好,在布局文件里直接放一个WebView控件就行。
WebView 的初始化有几个关键配置。第一,开启 JavaScript 支持:webSettings.setJavaScriptEnabled(true)。第二,设置缓存模式:我用的LOAD_CACHE_ELSE_NETWORK,优先读缓存,缓存没有再去网络加载。第三,开启 DOM 存储:webSettings.setDomStorageEnabled(true),有些 HTML 页面依赖 localStorage 来存状态。第四,设置自适应屏幕:webSettings.setUseWideViewPort(true)和webSettings.setLoadWithOverviewMode(true)。
加载本地 HTML 文件用webView.loadUrl("file:///android_asset/help.html")。这里要注意,android_asset目录下的文件在打包时会原样保留,不会被编译。我把帮助文档的 HTML、CSS、JS 都放在src/main/assets/help目录下,加载的时候路径写对就行。
注意:WebView 默认不允许混合内容(HTTP 和 HTTPS 混用)。如果你的 HTML 里引用了 HTTP 的图片或脚本,需要在
webSettings里设置setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW)。但出于安全考虑,我建议尽量用 HTTPS 资源,或者把资源下载到本地再引用。
4.2 WebView 与原生代码的交互
帮助文档页里有一个“联系客服”的按钮,点击后需要调起原生的拨号界面。这个功能通过 JavaScript 接口来实现。我在 Java 代码里定义了一个WebAppInterface类,里面写了一个callPhone(String phoneNumber)方法,然后用webView.addJavascriptInterface(new WebAppInterface(this), "Android")注册进去。HTML 里的按钮点击事件调用Android.callPhone("10086")就能触发原生方法。
这里有个安全坑要注意:addJavascriptInterface在 Android 4.2 之前有漏洞,攻击者可以通过反射调用任意 Java 方法。虽然现在minSdkVersion都至少 21 了,这个漏洞已经修复,但还是建议只暴露必要的方法,并且给方法加@JavascriptInterface注解。另外,加载的 HTML 必须是可信来源,不要加载外部不可控的网页。
还有一个交互是 WebView 里的链接点击。默认情况下,点击链接会在 WebView 内部跳转。但帮助文档里有些链接是指向外部网站的,我希望用系统浏览器打开。这个通过WebViewClient的shouldOverrideUrlLoading方法来实现:判断 URL 的域名,如果是外部域名就返回true并调Intent打开系统浏览器,如果是内部锚点就返回false让 WebView 自己处理。
4.3 WebView 性能优化与内存管理
WebView 是个吃内存的大户,如果不注意管理,很容易导致 App 卡顿甚至崩溃。我在项目里做了几件事来优化。第一,在onDestroy里调用webView.destroy()释放资源。第二,把 WebView 从父容器里移除后再销毁:((ViewGroup) webView.getParent()).removeView(webView)。第三,如果页面不需要 JavaScript,就关掉 JavaScript 支持。
还有一个优化点是预加载。帮助文档页不是高频页面,但每次打开都要加载 HTML 和资源,有点慢。我在设置页的onCreate里提前创建了一个 WebView 实例并加载了 HTML,等用户真正点进帮助页时直接复用这个实例,打开速度明显快了不少。当然,预加载会占用一些内存,需要根据 App 的整体内存情况来权衡。
实操心得:WebView 的
loadUrl是异步的,页面加载完成会回调onPageFinished。如果你需要在页面加载完成后执行某些操作,比如注入 JavaScript 或者隐藏加载进度条,一定要在onPageFinished里做,而不是在loadUrl之后直接做。
5. 第四阶段:数据统计与图表展示
5.1 统计页的数据聚合逻辑
统计页要展示的数据包括:总任务数、已完成任务数、完成率、以及按优先级分布的任务数量。这些数据都是从 Room 数据库里聚合出来的。我写了几个查询方法,用@Query注解在TaskDao里定义 SQL。比如查总任务数:SELECT COUNT(*) FROM tasks。查已完成任务数:SELECT COUNT(*) FROM tasks WHERE is_completed = 1。
按优先级分布的数据稍微复杂一点,需要分组查询:SELECT priority, COUNT(*) FROM tasks GROUP BY priority。返回的结果是一个List<PriorityCount>,里面包含优先级和对应的数量。这个查询在数据量大的时候可能会慢,所以我加了一个索引在priority列上。Room 支持通过@Index注解在实体类上定义索引,我加的是@Entity(indices = {@Index("priority")})。
数据聚合的时机我选在了统计页的onResume里。每次用户切换到统计页,都重新查一遍数据库,保证数据是最新的。查询操作放在后台线程执行,查完通过runOnUiThread更新 UI。这个方案简单直接,对于任务数量在几千条以内的 App 来说完全够用。
5.2 图表库的选型与集成
图表库我选了 MPAndroidChart,这个库在安卓社区里用得比较多,文档也相对齐全。它支持折线图、柱状图、饼图等多种图表类型。我在统计页里用了两种:一个是饼图,展示任务按优先级的分布;另一个是柱状图,展示最近七天的任务完成数量。
集成 MPAndroidChart 的步骤不复杂。先在build.gradle里加依赖:implementation 'com.github.PhilJay:MPAndroidChart:v3.1.0'。然后在布局文件里放PieChart和BarChart控件。最后在 Java 代码里配置数据源和样式。饼图的配置包括设置数据条目、颜色、图例位置、以及是否显示百分比。柱状图的配置包括设置 X 轴标签、Y 轴范围、以及柱子的颜色。
这里有个细节:MPAndroidChart 的默认动画是开启的,图表加载时会有一个从无到有的动画效果。这个效果挺好看的,但如果数据更新频繁,动画会显得很晃眼。我在更新数据前调了chart.clear()清空旧数据,然后调chart.invalidate()刷新,同时把动画时间设短了一点,大概 300 毫秒。
5.3 图表数据的动态更新与交互
统计页的数据不是静态的,用户完成任务后回到统计页,图表应该反映最新的数据。我在onResume里重新查询数据库并更新图表。更新饼图的逻辑是:先构造ArrayList<PieEntry>,然后创建PieDataSet,设置颜色和标签,最后创建PieData并赋给图表。柱状图的更新类似,构造ArrayList<BarEntry>,创建BarDataSet,再创建BarData。
交互方面,MPAndroidChart 支持点击图表元素显示高亮和数值。我在饼图上加了OnChartValueSelectedListener,点击某个扇区时弹出一个 Toast 显示该优先级的任务数量。这个功能不是必须的,但能提升用户体验。另外,我还给图表加了描述文字,默认的描述文字是“Description”,我改成了“任务统计”,并且把位置调到了图表右下角。
注意:MPAndroidChart 的图表在数据为空时会显示一个“No chart data available”的提示。如果你不希望显示这个提示,可以调
chart.setNoDataText("")把文字设为空。但更好的做法是,在数据为空时显示一个自定义的空状态视图,而不是让图表显示默认提示。
6. 第五阶段:测试、调试与问题排查
6.1 常见崩溃与异常处理
项目开发过程中遇到的崩溃大致分几类。第一类是空指针异常,主要出现在数据库查询返回空结果时没有做判空处理。比如查某个任务,如果任务不存在,taskDao.getById(id)返回null,后面直接调task.getTitle()就崩了。解决办法是在使用前加判空,或者用Optional包装。
第二类是IllegalStateException,主要出现在主线程做数据库操作时。前面提到过,Room 不允许在主线程查数据库。我一开始没注意,后来把所有数据库操作都放到了ExecutorService里执行。这里有个小技巧:可以用LiveData配合Room的@Query注解,Room 会自动在后台线程执行查询,查询结果通过LiveData回调到主线程,省去了手动管理线程的麻烦。
第三类是Resources.NotFoundException,出现在引用不存在的资源时。比如在布局文件里写了一个@drawable/icon,但res/drawable目录下没有这个文件。这种问题在编译时通常不会报错,但运行时一加载布局就崩。解决办法是仔细检查资源引用,或者用 Android Studio 的 Lint 工具扫描一遍。
6.2 性能问题与优化手段
性能问题主要体现在三个方面:启动速度、列表滚动流畅度、以及内存占用。启动速度方面,我把一些非必要的初始化操作延迟到了onCreate之后,比如统计页的预加载 WebView 就放到了设置页的onCreate里,而不是 App 启动时就做。这样冷启动时间从原来的 2.3 秒降到了 1.6 秒左右。
列表滚动流畅度方面,除了前面提到的DiffUtil,我还做了图片加载的优化。任务列表里没有图片,但帮助文档页有。我用的是 Glide 来加载图片,开启了内存缓存和磁盘缓存。另外,RecyclerView的setHasFixedSize(true)也加上了,这个设置能让 RecyclerView 在 item 大小固定时跳过一些测量步骤,提升滚动性能。
内存占用方面,主要关注 WebView 和 Bitmap。WebView 在页面销毁时一定要调destroy(),Bitmap 在使用完后要调recycle()。我还用 Android Studio 的 Memory Profiler 抓了几次内存快照,发现有一个地方在onDraw里创建了Paint对象,导致频繁 GC。后来把Paint对象提到成员变量里初始化,问题就解决了。
6.3 兼容性测试与适配
兼容性测试我覆盖了 Android 8.0 到 Android 14 这几个主要版本,以及不同屏幕尺寸和分辨率的设备。测试过程中发现的问题主要有两个。一个是 Android 12 之后,PendingIntent必须指定FLAG_IMMUTABLE或FLAG_MUTABLE,否则会崩。我用的地方是通知栏,加上了FLAG_IMMUTABLE就好了。
另一个是 Android 13 之后,通知权限需要动态申请。我在设置页里加了一个通知开关,打开时先检查权限,没有权限就调requestPermissions申请。用户拒绝后,下次再点开关会引导去系统设置里手动开启。这个流程在 Android 13 以下的版本不需要,所以代码里做了版本判断。
屏幕适配方面,我用了ConstraintLayout的百分比布局和dp单位,大部分设备上显示都正常。但在一些小屏设备上,统计页的图表有点挤。后来我给图表加了最小高度限制,并且在小屏设备上把饼图和柱状图改成上下排列,而不是左右排列。这个适配通过res/layout-sw600dp目录来实现,为不同屏幕宽度提供不同的布局文件。
7. 第六阶段:打包上架与后续维护
7.1 签名配置与打包流程
打包上架的第一步是生成签名文件。我用的是 Android Studio 的“Generate Signed Bundle / APK”功能,选择创建新的 keystore。keystore 的密码和别名密码一定要记牢,丢了就没办法给同一个 App 发更新了。keystore 文件我备份了三份,一份在本地,一份在云盘,一份在密码管理器里。
签名配置我写在了build.gradle里,用signingConfigs块定义。这样每次打包不用手动选签名文件,直接跑./gradlew assembleRelease就行。打包格式我选了 AAB(Android App Bundle),因为 Google Play 现在要求用 AAB 格式,国内应用市场对 APK 的接受度更高,所以我两个都打了。AAB 用于 Google Play,APK 用于国内市场。
注意:打包前记得把
build.gradle里的minifyEnabled设为true,开启代码混淆和资源压缩。混淆规则写在proguard-rules.pro文件里。WorkBuddy 生成的代码有一些反射调用,需要在混淆规则里保留对应的类和方法,否则混淆后运行会崩。
7.2 应用市场素材准备与审核要点
应用市场审核需要准备的材料包括:应用图标、截图、应用描述、隐私政策链接。图标我做了五个尺寸:48x48、72x72、96x96、144x144、192x192。截图我截了五张,分别展示任务列表、任务编辑、统计图表、设置页、帮助文档页。应用描述我写了两百字左右,重点突出任务管理和数据统计这两个核心功能。
隐私政策是个容易被忽视但很重要的东西。如果你的 App 收集了用户数据,比如设备信息、使用日志,必须在隐私政策里说明收集了什么、用来做什么、怎么保护。我的 App 只在本地存储任务数据,没有上传服务器,所以隐私政策写得比较简单。但即便如此,应用市场还是要求提供隐私政策链接,我放在了一个静态页面上。
审核被拒的情况我也遇到过一次。第一次提交时,应用截图里包含了“最佳任务管理工具”这样的绝对化用语,被驳回了。后来把描述改成“一款简洁的任务管理工具”就通过了。所以描述里不要用“最”、“第一”、“唯一”这类词,审核人员对这个比较敏感。
7.3 版本迭代与用户反馈处理
上架后的第一个版本是 1.0.0,上线一周收到了十几条用户反馈。反馈主要集中在两点:一是希望支持任务分类,二是希望统计页能按周、按月查看。这两个需求都不复杂,我在 1.1.0 版本里加上了。任务分类通过在Task实体里加一个category字段实现,统计页的时间范围切换通过查询条件里的日期范围来实现。
版本迭代的节奏我控制在两到三周一个小版本。每个版本只做一到两个核心功能,不做大而全的更新。这样既能快速响应用户需求,又能控制测试范围,降低引入新 bug 的风险。版本号我用的是语义化版本,主版本号在有不兼容改动时升,次版本号在有新功能时升,修订号在修 bug 时升。
用户反馈的收集渠道主要是应用市场的评论区和邮件。评论区的反馈比较零散,但能反映普遍问题。邮件的反馈更具体,通常附带截图和复现步骤。我建了一个简单的表格来跟踪反馈,每条反馈记录来源、描述、优先级、处理状态。这个表格帮我理清了哪些问题需要优先解决,哪些可以放到后面的版本。
8. 十六个坑的复盘与可复用经验
8.1 环境与构建相关的坑
第一个坑是 JDK 版本不匹配。WorkBuddy 要求 JDK 17,我一开始用的是 JDK 11,结果启动时报了一堆类找不到的错误。换成 JDK 17 后问题解决。第二个坑是 Gradle 版本和 AGP 版本不兼容。AGP 8.1 要求 Gradle 8.0 以上,我一开始用的 Gradle 7.5,构建时报版本不匹配。第三个坑是 Android Studio 的 SDK 路径配置错误,导致构建时找不到 SDK。在local.properties里正确配置sdk.dir后解决。
第四个坑是依赖冲突。我同时引入了两个网络库,它们依赖了不同版本的 OkHttp,导致运行时崩溃。解决办法是用./gradlew app:dependencies查看依赖树,然后用exclude排除掉冲突的版本。第五个坑是混淆规则没写全,Release 包运行时崩溃。解决办法是先在 Debug 包上测试,确认没问题后再打 Release 包,并且仔细检查混淆规则。
8.2 开发与调试相关的坑
第六个坑是 Room 数据库的主线程限制。前面提过,所有数据库操作都要放到后台线程。第七个坑是 WebView 的内存泄漏。WebView 在onDestroy里必须调destroy(),并且要从父容器移除。第八个坑是RecyclerView的notifyDataSetChanged()导致性能问题,换成DiffUtil后解决。第九个坑是ConstraintLayout的约束写错导致布局错乱,用 Layout Inspector 工具排查后修正。
第十个坑是日期格式化时的时区问题。我用SimpleDateFormat格式化日期,没有指定时区,导致在不同时区的设备上显示不一致。后来改成用java.time包下的LocalDate和DateTimeFormatter,并显式指定时区。第十一个坑是SharedPreferences的apply()和commit()混用。apply()是异步的,commit()是同步的,混用可能导致数据不一致。我统一用apply(),并且在需要立即读取的地方用commit()。
8.3 上架与运营相关的坑
第十二个坑是签名文件丢失。我有个朋友把 keystore 文件弄丢了,结果没办法给 App 发更新,只能重新上架一个新 App。所以 keystore 一定要备份。第十三个坑是应用截图包含敏感信息,比如真实的用户数据、测试账号密码。截图前一定要用测试数据,并且检查有没有暴露隐私。第十四个坑是隐私政策链接失效,审核时被拒。隐私政策页面要保证长期可访问。
第十五个坑是版本号忘记更新。每次发版前都要检查versionCode和versionName有没有改。versionCode必须递增,否则应用市场会拒绝上传。第十六个坑是更新日志写得太简单。更新日志要写清楚这个版本改了什么、修了什么,用户看了才知道要不要更新。我一般写三到五条,每条一句话,重点突出新功能和重要修复。
8.4 可复用的经验清单
把上面的坑整理成一份可复用的清单,下次做新项目时可以直接对照检查。环境方面:确认 JDK 版本、Gradle 版本、AGP 版本三者兼容;配置好 SDK 路径;检查依赖冲突。开发方面:数据库操作放后台线程;WebView 及时销毁;列表用 DiffUtil;布局用 ConstraintLayout;日期处理用 java.time。上架方面:备份 keystore;截图用测试数据;隐私政策可访问;版本号递增;更新日志写清楚。
这份清单我放在项目的 README 里,每次发版前过一遍。虽然不能覆盖所有问题,但能避免大部分低级错误。项目从立项到上架,前后大概改了三十多个文件,写了四千多行 Java 代码,加上 HTML 和配置文件,总共五千行左右。这个规模对于一个人来说不算小,但有了 WorkBuddy 的辅助,加上合理的阶段划分,最终还是按时交付了。
最后分享一个小心得:开发过程中遇到问题,先查官方文档,再查社区论坛,最后再问人。官方文档通常是最准确的,社区论坛能提供实际案例,问人虽然快但容易得到不完整的答案。另外,养成写开发日志的习惯,每天花了多少时间、做了什么、遇到什么问题、怎么解决的,都记下来。这些日志在复盘和写更新日志时特别有用。