免费获取学习方案
ARTICLE DETAIL

资讯详情

深耕编程基础知识与建站技术分享的一线实战洞察。

Android Studio精美计算器实战:从UI到打包的完整指南

Android Studio精美计算器实战:从UI到打包的完整指南 简介一个基于Android Studio实现的仿MIUI风格计算器项目面向Android入门开发者以项目实战方式演示了UI布局、事件监听与运算逻辑三个核心环节。整个资源包含957个文件压缩包约21.35MB其中xml布局与配置文件292个、png界面图片276个、java源代码22个、class编译产物44个另有gradle构建脚本、jar依赖库和可直接安装的apk结构完整便于按需查阅。目前已有2191人学习下载适合在校学生或转行开发者作为第一个完整App练手项目。项目不仅包含计算器基础的四则运算与连续表达式处理还在UI上参考了MIUI计算器设计覆盖ConstraintLayout约束布局、自定义按钮样式、点击事件绑定等要点借助源码、构建配置与APK读者可对照运行结果逐步理解Android应用从界面设计到功能实现的全流程便于按自己的需求继续扩展和二次开发。1. 简易计算器带上精美UI为什么是Android Studio最值得复刻的练手工程新学 Android 的人最容易卡在第一步想做个天气应用要联网、要解析 JSON、要申请权限想做个记账应用要引入数据库、要处理生命周期。唯独计算器这个项目不碰网络、不申请权限、不依赖后端一个 Activity 从头写到尾就能装进手机。而这个标题里的关键不是“计算器”是“精美UI”——同一个逻辑有人做出来是蓝底白字的系统默认控件有人做出来是圆角、按压反馈、双色配色都到位的成品。对刚装好 Android Studio 想跑通第一个真机项目的初学者、对想巩固 Java 与资源文件基础的学生、对要给内部工具做个小表单计算器的开发者这都是最合适的练手目标。我复刻这类工程时发现一个规律真正花时间的不是加减乘除是按钮状态、输入边界、布局适配这些细节。所以本文顺着一条完整落地路径来写先搭工程与 values 资源骨架再写核心计算逻辑然后做 drawable 圆角 UI最后解决几个高频翻车问题收尾在签名打包和冒烟测试上。你跟着做完得到的不是一堆散代码是一个能直接装进手机、给别人演示的计算器。2. 新建工程与 values 目录先把资源骨架搭对再写一行逻辑2.1 选对模板Empty Views Activity 与无 ActionBar 主题的取舍Android Studio 的新建项目向导里模板名称跟着版本在变。常见做法是选择 Empty Views Activity而不是 Empty Activity 或 Empty Compose Activity。原因很直接这个标题的项目要用 XML 布局做 UI而 Empty Compose Activity 默认生成的是 Jetpack Compose 的 Kotlin 代码里面的setContent { }和我们要讲的自定义 drawable、GridLayout、selector 完全不搭。选择 Empty Views Activity 后工程会生成一个activity_main.xml和对应的MainActivity这是最接近“一个界面配一个逻辑文件”的结构计算器项目不需要再拆 Fragment。另一个容易忽略的选项是主题。新模板通常给的是Theme.MaterialComponents.DayNight.NoActionBar这个主题去掉了 ActionBar。我建议保留它因为计算器顶部不需要标题栏标题栏会挤占屏幕高度。如果你在新建工程时没有直接选到 NoActionBar 系列后面也来得及改在themes.xml里把父主题换掉即可。很多初学者被“adds nothing to the screen”这句话误导实际 NoActionBar 只是隐藏了顶栏布局坐标不会受影响。在这个阶段还要确认 SDK 版本。Gradle 同步失败是新手最常见的拦路虎表现是“androidstudio打不开”工程或者一直转圈。多数情况是 AGPAndroid Gradle Plugin版本和 Gradle 版本不匹配不是项目代码问题。我一般直接把build.gradle里的compileSdk设成机器上已安装的 SDK 平台版本AGP 用 Android Studio 自带推荐值不主动追新。2.2 创建 values 资源colors、dimens、themes 三个 XML 怎么填在写布局之前先把资源目录准备好。在app/src/main/res目录上右键选择 New → Android Resource FileDirectory 选values这就是热词里常被问到的“androidstudio怎么创建values”。实际上这个目录新建工程时已经存在里面至少有一个themes.xml。问题是很多人把颜色、字号、间距全部写死在布局文件里后期想调色只能一个一个按钮改非常痛苦。我习惯在 values 下维护三个文件每个文件只干一件事。第一个是colors.xml集中管理全部颜色布局和 drawable 里都不直接写#FF6200EE这种裸值而是引用color/xxx。第二个是dimens.xml管理按钮高度、圆角半径、字号、间距。第三个是themes.xml管理全局主题属性。这个习惯在计算器这种小工程上看起来有点“过度设计”但当你把按钮数量加到 20 个时改一个圆角半径只需要动一个值而不是全局搜索替换 20 处。!-- res/values/colors.xml -- resources color namebg_dark#263238/color color namebtn_number#37474F/color color namebtn_number_pressed#546E7A/color color namebtn_operator#FF9800/color color namebtn_operator_pressed#F57C00/color color namebtn_equal#E64A19/color color namebtn_equal_pressed#D84315/color color namedisplay_text#FFFFFF/color color namedisplay_hint#90A4AE/color /resources!-- res/values/dimens.xml -- resources dimen namebtn_height64dp/dimen dimen namebtn_radius16dp/dimen dimen namedisplay_height120dp/dimen dimen namedisplay_text_size40sp/dimen dimen namespacing8dp/dimen /resources这两个文件是配套的。colors.xml用的是 Material Design 的深色质感配色背景偏深灰蓝数字键比背景亮一级运算符用橙色系。dimens.xml里的dp和sp分工明确按钮高度、圆角、间距这类几何尺寸用dp因为它在不同像素密度屏幕上保持物理尺寸一致显示区字号用sp因为它会跟随系统字体缩放。后面第 5 章会专门讲sp在个别手机上带来的适配坑这里先记住结论。2.3 用 GridLayout 把计算器拆成五行四列的按钮布局计算器界面结构不复杂但选对布局容器能让代码短一半。常见做法是用 GridLayout而不是嵌套三个 LinearLayout。嵌套方案的问题是权重计算繁琐而且每一行都要写layout_weight按钮宽度稍有不一致就会对不齐。GridLayout 设置columnCount4和rowCount5后每个按钮用layout_columnWeight和layout_rowWeight分配权重宽高自动均分。顶部显示区放在 GridLayout 外面单独占一个 TextView高度用display_height固定。这样做的原因是显示区宽度要横跨整个屏幕放在 GridLayout 内部需要layout_columnSpan4虽然也能实现但还要处理它的高度权重与按钮行一致的问题不如拆出来直接layout_widthmatch_parent省事。显示区下方才是按钮网格这种上下结构在 Android 里叫线性布局套网格布局是最稳妥的写法。!-- res/layout/activity_main.xml 骨架 -- LinearLayout android:layout_widthmatch_parent android:layout_heightmatch_parent android:orientationvertical android:backgroundcolor/bg_dark TextView android:idid/display android:layout_widthmatch_parent android:layout_heightdimen/display_height android:gravitybottom|end android:padding16dp android:textSizedimen/display_text_size android:textColorcolor/display_text android:maxLines1 android:ellipsizestart tools:text123456789 / GridLayout android:layout_widthmatch_parent android:layout_height0dp android:layout_weight1 android:columnCount4 android:rowCount5 Button android:idid/btn_clear android:layout_columnWeight1 android:layout_rowWeight1 android:layout_margindimen/spacing android:textC / !-- 其余按钮按行列顺序补齐 -- /GridLayout /LinearLayout这里涉及 Android Studio 里最常用的几个 UI 控件TextView、Button、GridLayout。注意我没有用 EditText 做显示区这是刻意选择——计算器的结果显示区域是只读的EditText 会弹出系统键盘还会触发光标闪烁纯展示用 TextView 加gravitybottom|end更干净。每个 Button 的layout_columnWeight1和layout_rowWeight1保证四列五行的格子均匀分配layout_margin制造按钮间距。真正的计算器键盘布局是第一行 C、±、%、÷第二行 7 8 9 ×第三行 4 5 6 −第四行 1 2 3 第五行 0、小数点、退格、等号。这个布局注意第五行只有三个键等号键应该占两行而不是和退格挤一行GridLayout 中用layout_rowSpan2实现后面第 4 章给完整代码。3. 计算器核心逻辑不做表达式解析用输入缓冲加状态复位3.1 为什么简易计算器要避开表达式解析器如果去搜索“java高级计算器”会看到很多项目引入 rhino、exp4j 这类表达式解析库或者在代码里维护一棵 AST 语法树。这种方案能做括号、能做函数但对一个三行两行的简易计算器是过度设计。引入第三方库意味着要处理 jar 包与依赖冲突还要学习它的 API自己写语法树更是把简单问题复杂化。标题说的是“简易计算器”核心诉求是用户连续输入数字和运算符按等号得到结果支持连乘连除边界情况不崩溃。所以我的选择是基于输入缓冲的状态机用一个字符串保存用户当前输入用一个布尔量记录“刚刚按过等号”。数字键往缓冲里追加字符运算符键在特定条件下追加或替换等号键触发解析计算。这个方案不依赖任何库纯 Java 几十行就能写完而且逻辑完全可控出问题可以直接调试。它的边界在于不支持括号、不支持一元负号但这些对“简易计算器”是合理取舍按钮上根本没有括号键。3.2 输入缓冲与连续运算StringBuilder 的 append 与清空时机核心数据结构是StringBuilder配合一个TextView做实时显示。每次点击数字键执行append(digit)点击运算符先判断缓冲里最后一位是不是运算符如果是就替换而不是追加避免出现12这种非法表达式。这里有个容易漏的状态clearFlag它表示“刚按过等号下一次输入数字要清空缓冲”。比如计算完12315后屏幕显示 15此时按下数字 7正确逻辑是清空缓冲重新输入7而不是得到157。public class MainActivity extends AppCompatActivity implements View.OnClickListener { private TextView display; private StringBuilder input new StringBuilder(); private boolean clearFlag false; // 等号后输入数字需要清空 Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); display findViewById(R.id.display); // 绑定全部数字与运算符按钮到同一个点击监听 int[] btnIds { R.id.btn_0, R.id.btn_1, R.id.btn_2, R.id.btn_3, R.id.btn_4, R.id.btn_5, R.id.btn_6, R.id.btn_7, R.id.btn_8, R.id.btn_9, R.id.btn_point, R.id.btn_plus, R.id.btn_minus, R.id.btn_mul, R.id.btn_div, R.id.btn_equal, R.id.btn_clear, R.id.btn_backspace }; for (int id : btnIds) { findViewById(id).setOnClickListener(this); } } Override public void onClick(View v) { int id v.getId(); if (id R.id.btn_clear) { input.setLength(0); display.setText(0); clearFlag false; return; } if (id R.id.btn_backspace) { if (input.length() 0) { input.deleteCharAt(input.length() - 1); } display.setText(input.length() 0 ? 0 : input.toString()); return; } if (id R.id.btn_equal) { calculate(); return; } // 数字与运算符共同走这段逻辑 String key ((Button) v).getText().toString(); if (clearFlag) { input.setLength(0); // 新数字开始清掉上一次结果 clearFlag false; } if (isOperator(key)) { if (input.length() 0) return; char last input.charAt(input.length() - 1); if (isOperator(String.valueOf(last))) { input.replace(input.length() - 1, input.length(), key); display.setText(input.toString()); return; } } else { if (..equals(key) input.indexOf(.) ! -1) return; // 同一数字内不能有两个小数点 if (input.length() 0 ..equals(key)) input.append(0); // 首键是点补0 } input.append(key); display.setText(input.toString()); } private boolean isOperator(String s) { return .equals(s) || -.equals(s) || *.equals(s) || /.equals(s); } }这段代码有四个关键参数和状态。setLength(0)是清空 StringBuilder 最高效的方式比new StringBuilder()少一次对象分配。clearFlag是状态机里最重要的开关它只在两种情况下被置真按下等号计算成功或者计算出错。input.indexOf(.)用来判断当前数字里是否已经有小数点注意它判断的是整个缓冲字符串如果用户输入1.23.4在追加第二个小数点之前缓冲里已经有两个点但这不影响判断——因为前面的点属于第一个操作数第二个操作数要单独判断就会漏判。这个问题放在第 5 章展开。((Button) v).getText().toString()获取按钮文本是这里最巧的一招不需要为每个按钮写一段点击逻辑按钮上的文字就是输入内容代码量和控件 id 解耦。3.3 等号计算的实现先乘除后加减的最小双栈代码按等号后进入calculate()。这里的算法选型要满足两个硬要求一是23*4必须算出 14 而不是 20即乘除优先于加减二是代码要短短到初学者能看懂。满足条件的经典方案是双栈求值一个栈存数字一个栈存运算符。遍历输入缓冲遇到数字就入数字栈遇到运算符就先处理栈里优先级不低于当前运算符的旧运算符再把当前运算符压栈。遍历结束后依次弹出所有剩余运算符栈顶数字就是结果。private void calculate() { if (input.length() 0) return; try { double result evaluate(input.toString()); display.setText(formatResult(result)); input.setLength(0); input.append(formatResult(result)); // 把结果放回缓冲支持连续运算 clearFlag true; } catch (ArithmeticException e) { display.setText(除数为0); input.setLength(0); clearFlag true; } } private double evaluate(String expr) { StackDouble numbers new Stack(); StackCharacter ops new Stack(); for (int i 0; i expr.length(); i) { char c expr.charAt(i); if (Character.isDigit(c) || c .) { StringBuilder sb new StringBuilder(); while (i expr.length() (Character.isDigit(expr.charAt(i)) || expr.charAt(i) .)) { sb.append(expr.charAt(i)); i; } i--; numbers.push(Double.parseDouble(sb.toString())); } else if (isOperator(String.valueOf(c))) { while (!ops.isEmpty() precedence(ops.peek()) precedence(c)) { numbers.push(applyOp(ops.pop(), numbers.pop(), numbers.pop())); } ops.push(c); } } while (!ops.isEmpty()) { numbers.push(applyOp(ops.pop(), numbers.pop(), numbers.pop())); } return numbers.pop(); } private int precedence(char op) { if (op || op -) return 1; if (op * || op /) return 2; return 0; } private double applyOp(char op, double b, double a) { switch (op) { case : return a b; case -: return a - b; case *: return a * b; case /: if (b 0) throw new ArithmeticException(); return a / b; default: return 0; } } private String formatResult(double result) { if (result Math.floor(result)) { return String.valueOf((long) result); } return String.valueOf(result); }双栈算法的核心是precedence(ops.peek()) precedence(c)这个比较符号。以23*4为例读到时数字栈是 [2]运算符栈空直接入栈读到*时数字栈是 [2,3]在栈顶precedence()是 1小于precedence(*)的 2所以*直接入栈读到4后表达式结束最后统一弹出先算3*412再算21214。如果把比较符号写成同一表达式会先算235再5*420这是最经典的翻车点。applyOp里的弹栈顺序也有讲究。调用时传参是ops.pop(), numbers.pop(), numbers.pop()第一个pop()得到 b第二个pop()得到 a。数字栈是后进先出1-2入栈后栈顶是 2先弹出的就是 2即 b所以a-b才是1-2-1。写成b-a会得到1减法和除法全反。这个坑我见过太多次全是低级错误但结果完全不对。formatResult负责把整数结果去掉小数点因为7/1显示成7.0会让用户觉得是 bug。clearFlagtrue把当前结果送回输入缓冲用户可以直接按运算符继续运算不用先清空再输入。4. 精美UI从 drawable 开始圆角、按压与配色不引入一张图片4.1 shape drawable 做圆角按钮XML 参数与按压联动很多初学者做“精美UI”的第一反应是找图标、找背景图。实际上 Android 原生 drawable 体系里有一类 shape drawable纯 XML 就能画圆角矩形、描边、渐变、按压变色,计算器这种规则按钮网格根本不需要任何图片素材。右键res/drawable目录新建btn_number_bg.xml内容是一个selector里面包两个item一个对应按压态android:state_pressedtrue一个对应默认态。每个 item 内部再嵌一个shape定义圆角。!-- res/drawable/btn_number_bg.xml -- selector xmlns:androidhttp://schemas.android.com/apk/res/android item android:state_pressedtrue shape android:shaperectangle solid android:colorcolor/btn_number_pressed / corners android:radiusdimen/btn_radius / /shape /item item shape android:shaperectangle solid android:colorcolor/btn_number / corners android:radiusdimen/btn_radius / /shape /item /selector把这段 selector 设为按钮的android:background按下时颜色自动切换不需要在 Java 代码里监听onTouch。按钮的按压反馈是“精美UI”的底线没有它界面再好看都有一种死板感。corners的radius用dimen/btn_radius引用所有按钮圆角统一为 16dp视觉上才能成为一个整体。数字键、运算符键、等号键分别建一个 selector只是颜色不同结构和这个完全一样。这里有三个容易犯的细节错误。第一个是按钮默认自带背景直接设android:background会覆盖掉 Material 按钮原有的水波纹导致点击没有动画反馈解决方法是同时保留 selector 的颜色变化水波纹属于RippleDrawable的高级用法简易项目不做。第二个是state_pressed的 item 必须写在最前面selector 按顺序匹配写到后面永远不会生效。第三个是shape的默认类型是 rectangle矩形需要显式声明圆角圆角值单位是 dp写成 px 在低分辨率屏幕上会显得圆角过大或过小。4.2 数字键与运算符键的双色体系与对比度校验配色的目标不是“鲜艳”是“一眼能看出哪类按钮可点、哪类按钮危险”。计算器按钮分为三类数字键、运算符键、清理/退格键。我采用深色背景上的双色体系数字键用比背景亮一档的蓝灰色#37474F运算符键用橙色#FF9800等号键用更深的橙红#E64A19。这个配色的依据是 Material Design 的 contrast guidelines前景与背景的对比度至少在 3:1 以上运算符键作为高频交互区域需要更醒目。按钮类型默认色按压色前景文字色数字/小数点#37474F#546E7A#FFFFFF运算符−×÷#FF9800#F57C00#212121等号#E64A19#D84315#FFFFFF清理/退格#455A64#546E7A#90A4AE文字颜色也要跟着场景走。数字键白色文字是因为背景蓝灰较深运算符按键背景是亮橙色白色文字对比度反而不够用深色文字#212121更清晰。清理键我故意把文字颜色调暗一档降低它的视觉权重避免用户频繁误触。这套值写进 2.2 节的colors.xml后所有按钮只需改android:background和android:textColor两个属性。如果你把工程放到真机上发现颜色发灰先检查是不是主题的colorButtonNormal在作怪把按钮的backgroundTint显式设为空或直接不依赖主题色。4.3 显示区 TextView 的字体字号与结果溢出处理显示区是用户第一眼看到的区域它的细节决定整个应用的质感。系统默认的textSize是 14sp对计算器来说太小我在dimens.xml里已经定义为 40sp。这里要处理的问题是“Android Studio 常用的 UI 控件”中 TextView 的maxLines和ellipsize——当结果位数太长时显示区不能换行也不能让字体自动缩小到看不清。在 2.3 节的布局骨架里已经写了maxLines1和ellipsizestartellipsizestart的含义是超长时省略头部保留尾部因为计算结果最右侧的位数才是最关键的用户关心的是最后几位。有一个容易被忽略的显示区细节fontFamily。按钮上的数字用系统默认字体即可但显示区的数字建议用sans-serif系列中的等宽变体sans-serif-medium这样所有数字宽度一致连续输入时文本不会左右跳动。在 XML 里写作android:fontFamilysans-serif或sans-serif-medium不需要额外下载字体文件。另一个细节是显示区背景要与按钮网格有区分我在实际工程里会给显示区加一个#1E2A32的深色底和页面背景#263238拉开层次再配合layout_margin让显示区自带边距。TextView android:idid/display android:layout_widthmatch_parent android:layout_heightdimen/display_height android:backgroundcolor/display_bg android:fontFamilysans-serif-medium android:gravitybottom|end android:maxLines1 android:ellipsizestart android:textColorcolor/display_text android:textSizedimen/display_text_size /这里再强调一次 UI 线程问题计算器的计算全部发生在onClick里属于主线程。23*4的耗时是微秒级不会出现 ui界面卡顿。真正的卡顿隐患是formatResult里对超大 double 的字符串转换如果用户连续输入几十位数字double会溢出成 Infinity显示区直接输出 “Infinity”。处理方式是在calculate()里判断Double.isInfinite(result)是则显示“超出范围”而不是一串乱码。这个检查代码量极小但能避免真机上最尴尬的演示事故。5. 避坑计算器从能跑到好用的 5 个常见问题排查记录5.1 连续按等号结果错乱运算符缓冲复位的时机问题现象计算12315后屏幕正确显示 15但紧接着再按一次等号结果变成123318或者直接变成 0。原因等号计算后我把结果写回了输入缓冲并设置clearFlag但用户在结果状态直接按等号时calculate()读取的是“15”这个只有数字没有运算符的缓冲evaluate 会正常返回 15看起来没毛病如果用户按的是运算符再按等号比如12315后按、按理想行为是18但实际可能拿到123这种尾部带运算符的非法表达式。解决在calculate()开头判断缓冲最后一位如果是运算符直接删掉再计算。这是状态机方案最容易漏的边界。private void calculate() { if (input.length() 0) return; // 去掉尾部残留的运算符例如 123 末尾的 char last input.charAt(input.length() - 1); if (isOperator(String.valueOf(last))) { input.deleteCharAt(input.length() - 1); } if (input.length() 0) return; // 继续原有计算逻辑 }5.2 输入第二个小数点被拦截失败contains 判断的边界现象输入1.2后想再输入3.4当按下小数点时没有任何反应第二个操作数的小数点输不进去。原因3.2 节的代码用input.indexOf(.) ! -1判断它检查的是整个缓冲字符串而不是当前操作数。1.2里已经有小数点所以后续所有小数点都被拦截。解决需要找到最后一个运算符的位置只对运算符之后的部分做小数点判断。这个坑体现了“简易逻辑”与“正确逻辑”之间的一条分界线。private boolean currentNumberHasPoint(String expr) { int idx -1; char[] ops {, -, *, /}; for (char op : ops) { idx Math.max(idx, expr.lastIndexOf(op)); } return expr.substring(idx 1).indexOf(.) ! -1; }5.3 除数为零崩溃挂掉try-catch 与提示文本的处理现象输入5÷0按等号应用直接闪退Logcat 里报ArithmeticException: divide by zero。原因applyOp中除数为零时 throw 了异常但calculate()没有捕获异常抛到 Android 框架层导致崩溃。解决3.3 节的calculate()已经把evaluate调用包在 try-catch 里这块逻辑要确保异常类型匹配。另一个容易漏的是Double.parseDouble在输入超长数字时抛NumberFormatException它不是ArithmeticException的子类需要单独捕获或者统一捕获Exception。我习惯在calculate()里捕获Exception把除零、格式错误、溢出全部统一处理为显示“输入错误”。5.4 真机底部被导航栏遮挡dp、sp 与屏幕适配的差异现象在预览和模拟器上布局完美装到华为或小米真机上最下面一行按钮被手势导航条挡住一半。原因根布局用了match_parent高度没有考虑系统导航栏占据的屏幕区域。解决给根 LinearLayout 设置android:fitsSystemWindowstrue让内容自动避开状态栏和导航栏或者用WindowInsets监听导航栏高度并给 GridLayout 加 padding。注意不要通过写死 dp 值的方式“预留”导航栏高度不同机型的导航栏高度差异巨大写死必然顾此失彼。fitsSystemWindows是性价比最高的方案一行属性解决大部分遮挡问题。5.5 结果区域不刷新误用 EditText 的 inputType 与文本监听现象点击数字按钮屏幕上的显示区没有任何变化但 Logcat 里能看到按钮响应。原因把显示区错用成了EditText且给它设置了android:inputTypenumber系统键盘弹出的同时代码里display.setText()也被系统文本监听干扰。解决确认显示区用TextView按钮点击后直接setText。如果坚持用 EditText必须加android:focusablefalse和android:cursorVisiblefalse否则会触发输入法弹窗。标题既然强调 UI就不要在这种地方因小失大只读区域一律用 TextView。这个问题的排查要点在于先确认findViewById拿到的控件类型再确认setText的调用时机两者都对了仍然不显示才考虑线程问题。6. 装进手机前的最后一步签名打包与 Monkey 冒烟验证开发调试时 Android Studio 用的是 debug 签名这种应用只能自己手机安装发给别人会被系统拦截。想把这个计算器当成一个拿得出手的小作品就要走一遍正式签名流程。在菜单里选择 Build → Generate Signed Bundle / APK选择 APK新建一个 keystore 文件。注意 keystore 的密码和别名要记牢Android 应用更新时如果签名不一致安装会直接失败这个没有后悔药。签名完成后勾选Signature Schemes V1 and V2V1 兼容老设备V2 是新版本验证方式两个都勾上最稳妥。打包出来的 APK 先用adb install装到自己手机上跑一遍再做一轮自动冒烟测试。Android SDK 自带一个 Monkey 工具可以随机生成触摸事件用来暴露崩溃问题。下面这条命令会在目标应用上随机点击 1000 次间隔 300 毫秒重点处理触摸事件占比 70%adb shell monkey -p com.example.calculator --throttle 300 --pct-touch 70 1000运行后观察 Logcat 里是否有FATAL EXCEPTION如果 Monkey 测试结束后应用还活着说明主要交互路径没有崩溃。这个方法的魅力在于不需要写一行测试代码随机乱点最容易触发连续等号、快速切换运算符这类手工测不全的场景。我自己的习惯是Monkey 跑完后手动再做一轮“连续运算 清空 退格”的边界操作比如输入0.00.0按等号再输入999999999*999999999看溢出提示最后锁屏再解锁确认界面状态没有错乱。这几个动作能覆盖 80% 的用户翻车场景。最后检查 APK 体积和对齐情况。build/outputs/apk/release目录下的 APK 应当只有几百 KB如果超过 1MB多半是误打进了 debug 版本或带入了多余资源。用zipalign -c 4 file.apk可以验证对齐Android Studio 打包默认会做只是命令行手动打包的人容易漏掉这一步未对齐的 APK 在部分设备上会有毫秒级的启动卡顿。整个流程走完这个简易计算器才算真正具备了安装条件有签名、有按压反馈、有异常兜底、有连续运算能力。严格说起来功能不如系统自带计算器但作为 Android 开发入门的第一块里程碑到这一步已经可以大方拿给朋友看了希望帮到你。本文还有配套的精品资源点击获取
返回列表