ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

Android注册页无数据库实现:输入校验与状态保存实战

Android注册页无数据库实现:输入校验与状态保存实战 简介这是一份面向Android开发初学者的入门级实战资源基于Android Studio与Java语言实现一个不含数据库的简单个人信息注册小应用。功能覆盖用户名与密码输入、单选性别、下拉选择地址、复选爱好点击提交后跳转结果页展示全部填写内容并对空输入给出提示结果页还可返回首页适合刚接触移动应用开发、想通过完整小实例熟悉界面控件与页面跳转的读者。资源包共495个文件约10.27MB以xml布局、json配置、flat与webp资源、dex与class字节码、java源码及gradle构建脚本为主另含apk成品与properties、jar等依赖文件结构贴近真实Android工程。目前已有846人学习下载可帮助读者快速理解Activity跳转、控件取值与简单校验的实现思路并对照源码自行修改扩展。1. 个人信息注册页为什么“无数据库版”反而是最好的起点很多人第一次打开 Android Studio想做的第一个能拿得出手的东西往往就是一个注册页。输入手机号、密码、确认密码点一下按钮弹个提示——听起来简单但真动手时卡人的地方从来不是界面而是“数据存哪”。一提到注册脑子里立刻蹦出数据库、后端接口、网络请求结果环境还没配好人已经劝退了。这篇要讲的就是把数据库这一层彻底拿掉所有校验在本地完成数据用内存或轻量持久化兜住跑起来就能看到完整交互。它解决的不是“生产级注册系统”而是让你在 Android Studio 里把 Activity、布局、输入校验、状态保存这条链路完整走一遍。适合刚装完 Android Studio、想找一个能跑通的最小闭环的新手也适合想快速验证 UI 交互、不想被后端拖住的老手。无数据库不等于没逻辑恰恰相反校验规则、错误提示、状态回显这些“真活”一个都不少。2. 从零搭出注册页布局、控件与输入约束2.1 先想清楚页面结构再动手拖控件注册页的布局没有玄学核心就三件事输入区、提示区、操作区。输入区放手机号、密码、确认密码提示区用来显示每条校验的错误信息操作区就是那个注册按钮。我一般用LinearLayout垂直排列外层套一个ScrollView防止小屏手机弹出软键盘后按钮被顶出屏幕——这个坑后面避坑章节还会细说。控件选型上手机号用EditText配inputTypephone密码用inputTypetextPassword。这里有个新手常忽略的点inputType不只是控制键盘类型它还影响系统是否对输入做自动填充、是否显示明文切换按钮。密码框如果写成text输入内容会赤裸裸显示出来既不安全也不专业。!-- activity_register.xml 核心结构 -- ScrollView xmlns:androidhttp://schemas.android.com/apk/res/android android:layout_widthmatch_parent android:layout_heightmatch_parent LinearLayout android:layout_widthmatch_parent android:layout_heightwrap_content android:orientationvertical android:padding24dp !-- 手机号输入 -- EditText android:idid/etPhone android:layout_widthmatch_parent android:layout_heightwrap_content android:hint请输入手机号 android:inputTypephone android:maxLength11 / !-- 密码输入 -- EditText android:idid/etPassword android:layout_widthmatch_parent android:layout_heightwrap_content android:hint请输入密码 android:inputTypetextPassword / !-- 确认密码 -- EditText android:idid/etConfirm android:layout_widthmatch_parent android:layout_heightwrap_content android:hint请再次输入密码 android:inputTypetextPassword / !-- 错误提示统一放这里 -- TextView android:idid/tvError android:layout_widthmatch_parent android:layout_heightwrap_content android:textColor#D32F2F android:visibilitygone / Button android:idid/btnRegister android:layout_widthmatch_parent android:layout_heightwrap_content android:text注册 / /LinearLayout /ScrollView这段布局里maxLength11是手机号的第一道硬约束超过 11 位根本敲不进去。tvError默认gone只有校验失败才显示避免空白占位。ScrollView包住整个LinearLayout是应对软键盘遮挡最省事的做法。2.2 输入校验的规则设计别等点了按钮才报错校验分两层一层是输入时的实时约束一层是点击注册时的集中校验。实时约束靠inputType和maxLength已经挡掉一部分但手机号格式、密码长度、两次密码是否一致这些必须在代码里判断。我一般把校验逻辑抽成一个独立方法返回错误信息字符串为空表示通过。这样按钮点击和后续可能的实时校验都能复用同一套规则不会出现“按钮说不行、实时提示说行”的精神分裂。// RegisterActivity.kt 中的校验方法 private fun validateInput(phone: String, pwd: String, confirm: String): String? { // 手机号11位且以1开头 if (phone.length ! 11 || !phone.startsWith(1)) { return 手机号格式不正确 } // 密码至少6位 if (pwd.length 6) { return 密码不能少于6位 } // 两次密码一致 if (pwd ! confirm) { return 两次输入的密码不一致 } return null // 全部通过 }参数说明phone、pwd、confirm分别来自三个EditText的text.toString().trim()。注意trim()一定要加用户从别处粘贴时很容易带首尾空格不加的话“密码不一致”会莫名其妙地触发。返回null代表校验通过这种“空即成功”的约定在 Kotlin 里配合?.let或if (error ! null)都很顺手。2.3 按钮点击与提示回显把结果说清楚点击注册按钮后先取输入值再调校验最后根据结果决定是弹 Toast 还是把错误写到tvError。这里有个体验细节错误信息写在页面上比 Toast 更友好因为 Toast 几秒就消失用户还没看清就没了。我一般两者结合——页面提示具体错误Toast 给一个轻量反馈。btnRegister.setOnClickListener { val phone etPhone.text.toString().trim() val pwd etPassword.text.toString().trim() val confirm etConfirm.text.toString().trim() val error validateInput(phone, pwd, confirm) if (error ! null) { // 页面内提示常驻可见 tvError.text error tvError.visibility View.VISIBLE } else { tvError.visibility View.GONE // 无数据库版这里只做本地回显不落库 Toast.makeText(this, 注册成功$phone, Toast.LENGTH_SHORT).show() } }逻辑说明校验失败时显示tvError并写入具体原因成功时隐藏错误提示用 Toast 回显注册的手机号。无数据库版的关键就在成功分支——没有INSERT、没有网络请求数据只活在当前页面。这不是偷懒而是把注意力集中在交互链路上。等你把这条链路跑顺了再往后接数据库或接口只是替换成功分支里那几行而已。3. 无数据库怎么“存”内存、Bundle 与轻量持久化3.1 内存单例最直接的数据落脚点无数据库不等于数据完全不留痕。最常见的做法是用一个单例对象在内存里存已注册的用户页面销毁前都能读到。这种方式适合演示和单机小工具进程被杀数据就没了但胜在零依赖、零配置。// UserStore.kt —— 内存单例 object UserStore { // key 用手机号value 用密码演示用真实场景别这么干 private val users mutableMapOfString, String() fun register(phone: String, pwd: String): Boolean { if (users.containsKey(phone)) return false // 已存在 users[phone] pwd return true } fun exists(phone: String): Boolean users.containsKey(phone) }参数说明users用mutableMapOf存手机号到密码的映射。register返回Boolean方便调用方判断是“注册成功”还是“手机号已存在”。这里刻意用手机号做 key是因为注册场景里手机号天然唯一比自增 ID 更贴近真实业务。注意这只是演示真实项目里密码绝不能明文存内存这里只是为了让你看清数据流向。3.2 用 Bundle 扛住屏幕旋转别让用户白填Android 有个经典翻车场景用户填完一屏信息手机一转屏Activity 重建所有输入清空。无数据库版尤其容易中招因为数据本来就没落盘。解决办法是用onSaveInstanceState把关键输入塞进 Bundle重建时再取出来。// 保存状态 override fun onSaveInstanceState(outState: Bundle) { super.onSaveInstanceState(outState) outState.putString(phone, etPhone.text.toString()) outState.putString(pwd, etPassword.text.toString()) outState.putString(confirm, etConfirm.text.toString()) } // 恢复状态放在 onCreate 里 override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_register) // ... 控件绑定 ... savedInstanceState?.let { etPhone.setText(it.getString(phone)) etPassword.setText(it.getString(pwd)) etConfirm.setText(it.getString(confirm)) } }逻辑说明onSaveInstanceState在 Activity 可能被销毁前调用把三个输入框的内容写进 Bundle。重建时savedInstanceState不为空就回填。参数 key 用字符串注意保存和读取的 key 必须完全一致大小写都不能错否则取出来是null界面看着像没保存一样。这个机制对无数据库版几乎是刚需因为一旦重建内存单例虽然还在但输入框内容不会自动恢复。3.3 SharedPreferences想跨启动保留时的轻量选择如果希望关掉 App 再打开还能看到上次注册的手机号可以用SharedPreferences。它本质是一个 XML 文件适合存少量键值对不适合存大量结构化数据。无数据库版里用它存“最近一次注册的手机号”刚刚好。// 写入 val sp getSharedPreferences(user_prefs, Context.MODE_PRIVATE) sp.edit().putString(last_phone, phone).apply() // 读取 val lastPhone sp.getString(last_phone, ) etPhone.setText(lastPhone)参数说明user_prefs是文件名MODE_PRIVATE表示仅本应用可读。apply()是异步写入不阻塞主线程如果要求写入后立刻读用commit()。读取时第二个参数是默认值这里给空字符串避免null导致setText崩溃。注意SharedPreferences不适合存密码演示里存手机号就够了别把敏感信息往里塞。4. 避坑与排查注册页最容易翻车的 5 个点4.1 软键盘弹出后按钮被顶飞现象点密码框软键盘升起注册按钮被挤到屏幕外用户找不到。原因布局没有滚动容器或者windowSoftInputMode设置不当。解决外层套ScrollView并在AndroidManifest.xml对应 Activity 上加android:windowSoftInputModeadjustResize让系统压缩可用高度而不是整体上推。4.2 转屏后输入全没了现象填完信息一转屏三个框全空。原因Activity 重建输入框状态未保存。解决按 3.2 节用onSaveInstanceState保存和恢复。注意如果用了android:configChanges强行阻止重建虽然能保住数据但会错过资源重载不推荐作为常规手段。4.3 密码框显示明文现象密码输入时直接可见。原因inputType写成了text而不是textPassword。解决改回textPassword。如果需要在明文和密文间切换用setTransformationMethod配合眼睛图标别直接改inputType否则键盘类型也会跟着变。4.4 手机号带空格导致校验失败现象用户粘贴手机号校验提示格式不正确但肉眼看着就是 11 位。原因粘贴内容首尾或中间带了空格。解决取值时统一trim()如果要求更严用replace( , )去掉所有空格再校验。这个坑血泪经验最多因为用户根本意识不到自己带了空格。4.5 Toast 在 Android 11 以上被限制现象自定义 Toast 在部分机型上不显示或显示异常。原因从 Android 11 开始系统对自定义 Toast 做了限制普通文本 Toast 不受影响。解决注册页的反馈用系统默认 Toast 即可别为了好看去自定义布局。如果确实需要复杂提示用Snackbar替代。5. 进阶技巧把注册页做成可复用的输入校验组件写到这儿注册页已经能跑通了。但如果你每个页面都复制一遍validateInput迟早会后悔。我一般会把校验规则抽成一个独立的Validator类用链式调用组合规则这样登录页、改密页都能直接复用。// Validator.kt —— 可复用的校验器 class Validator { private val rules mutableListOf() - String?() fun addRule(rule: () - String?): Validator { rules.add(rule) return this } // 返回第一条不满足的规则提示全通过返回 null fun validate(): String? { for (rule in rules) { val error rule() if (error ! null) return error } return null } } // 使用示例 val error Validator() .addRule { if (phone.length ! 11) 手机号格式不正确 else null } .addRule { if (pwd.length 6) 密码不能少于6位 else null } .addRule { if (pwd ! confirm) 两次密码不一致 else null } .validate()逻辑说明addRule接收一个返回String?的 lambda返回null表示该规则通过。validate按添加顺序逐条执行遇到第一条不通过就返回其提示短路后续规则。这种写法的好处是规则顺序即优先级手机号格式的提示会先于密码长度出现符合用户从上到下的填写习惯。参数说明每个 lambda 里直接捕获外层的phone、pwd、confirm变量所以规则定义要放在取值之后。如果规则需要跨页面复用可以把 lambda 改成接收参数的函数类型但那样调用会啰嗦一些按需取舍。验证这套组件是否可靠有个笨但有效的办法把边界值列成表格逐条手动过一遍。测试项输入预期提示手机号 10 位1380000000手机号格式不正确手机号不以 1 开头23800000000手机号格式不正确密码 5 位12345密码不能少于6位两次密码不一致123456 / 123457两次输入的密码不一致全部合法13800000000 / 123456 / 123456注册成功这张表我一般会贴在代码旁边改规则时先过表再提交。无数据库版没有后端兜底所有边界都得自己扛这张表就是你的后悔药。最后说个习惯每次改完校验规则我一定会在真机或模拟器上把转屏、切后台、粘贴带空格手机号这三个动作各做一遍。这三个动作覆盖了无数据库注册页 80% 的翻车场景花不了两分钟但能省下大量“明明代码没问题”的排查时间。希望帮到你。本文还有配套的精品资源点击获取
返回列表