ARTICLE DETAIL

资讯详情

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

Android无数据库注册功能实现:SharedPreferences与Activity实战

Android无数据库注册功能实现:SharedPreferences与Activity实战 简介这是一份基于Android Studio开发的轻量级用户注册功能实践项目面向Android移动应用开发初学者帮助理解UI组件交互、页面跳转与表单校验等核心基础概念。项目实现用户名与密码输入、性别单选、地址下拉选择、爱好复选框等典型注册字段并支持空值提示、提交后跳转至结果页完整展示所填信息以及返回首页功能全程无需数据库聚焦原生JavaXML开发流程。压缩包共495个文件包含88个XML布局与配置文件、134个Flat资源文件、128个JSON元数据及20个WebP图像资源辅以Gradle构建脚本、APK安装包与调试相关文件整体大小为10.27MB结构清晰便于逐模块学习与调试。已有846人下载学习配套代码完整可直接运行适合用于课堂实验、课程设计入门或自学练手是掌握Android基础控件与Activity生命周期的实用参考范例。 很多人学 Android 开发第一个真正有“业务感”的小项目往往就是注册登录。今天我来分享一个可以直接抄作业的 Android Studio 项目实现简单的个人信息注册无数据库版。这个版本不需要 SQLite、不需要联网也不引入任何第三方库只用系统自带的控件和 SharedPreferences就能跑通从界面输入、数据校验、本地持久化到页面跳转的完整闭环。适合刚学完 Activity、想动手做点东西的新手也适合做课程设计时先交一个可运行的轻量版本。之所以要写无数据库版是因为我见过太多同学一上来就研究 SQLite、Room结果界面还没画明白代码先崩在数据库初始化上了。把数据库去掉之后整个项目其实只剩下三件事搭界面、写逻辑、存数据。每一件事都能看得清清楚楚任何一个环节出问题你都能一眼定位。等这条链路跑通了再往里面加数据库难度会低很多。1. 项目概述与整体设计思路1.1 无数据库注册功能是什么能做什么这个项目的核心结构很简单一个 MainActivity 负责展示注册表单用户填写姓名、年龄、性别、电话等信息后点击注册按钮。程序先对输入内容做校验比如姓名不能为空、年龄必须是数字、手机号要符合 11 位规则。校验通过后数据以键值对的形式写入 SharedPreferences 文件然后跳转到一个新的 ResultActivity把刚才保存的信息展示出来。从功能上说它完成了注册模块的前半段采集信息、校验数据、保存数据。后半段——入真正的数据库、账号查重、登录验证——留给你后续扩展。单论“注册”这个场景纯本地无数据库版能应付不少轻量需求比如工具类 App 的本地配置、单机小游戏的玩家资料输入、企业内部演示 demo。它不是生产级方案但它的价值在于把 Android 开发的基本功完整暴露出来了布局与控件的配合、Activity 生命周期、事件回调、数据持久化、页面跳转。这五个点恰好是 Android 入门最重要的骨架。整个数据流是单向的MainActivity 表单 → 校验 → SharedPreferences → ResultActivity 展示。这条链路上每个环节都是独立的除了 SharedPreferences 是唯一的“存储”其他全是界面和逻辑。对新手来说这样的结构非常有利于排错写错了也知道改哪里。1.2 为什么推荐初学者先做无数据库版很多教材一上来就把 SQLiteOpenHelper、Cursor、ContentValues 全堆给你初学者很容易懵。因为数据库一引入你要同时处理两套复杂度一套是界面和事件逻辑另一套是数据库生命周期管理。一旦代码报错你很难判断是界面问题还是数据库操作问题排查起来特别劝退。SharedPreferences 就友好得多它本质就是一个保存在 /data/data/包名/shared_prefs/ 目录下的 XML 文件。你只需要记住一句话它就是一份“键值对”字典。用 putString 存进去用 getString 取出来逻辑透明到几乎没有坑也不会遇到忘记关连接、并发读写这类数据库才有的问题。我经常打一个比方数据库是仓库SharedPreferences 是抽屉。你只是临时注册一个用户、存一条个人信息用一个抽屉就够了。等你需要管理大量结构化数据、做条件查询、维护表间关系的时候再引入仓库——也就是 SQLite 或 Room。这个类比能帮你建立“什么时候该用什么工具”的判断力而不是所有数据一股脑都往数据库里塞。当然无数据库版的短板也很明显它只能存一份数据多注册几个用户就会互相覆盖。这个局限性你不用回避它恰恰是你下一步学习数据库的动机来源。2. 环境准备Android Studio 安装与项目创建2.1 安装与配置重点SDK、虚拟化、汉化虽然这个项目本身不难但我见过大量新手卡在环境上代码还没写一行Android Studio 就没跑起来。所以这里把几个高频问题一起说了。安装时注意三点。第一SDK 路径不要放在默认的 C 盘。现在的 SDK 体积动辄几十个 GC 盘空间不足会导致编译失败、模拟器卡顿。第二首次启动选择 Standard 模式让它自动下载 SDK Platform 和 Build Tools。如果你下载速度很慢可以把下载源切换为国内镜像源这属于常规操作。第三模拟器能不能顺利启动取决于 Windows 虚拟化功能有没有开启。Intel CPU 一般用 HAXMAMD CPU 通常走 Hyper-V。如果你的电脑不支持虚拟化或者开虚拟化后仍然很卡我建议直接用真机调试——用 USB 线连接手机开启开发者模式运行速度和稳定性都远好于模拟器。关于汉化Android Studio 自带中文语言包插件。打开 Settings → Plugins搜索 Chinese安装后重启就是中文界面。不过我个人建议英文界面虽然一开始有点别扭但查资料、看报错都更方便这个看个人习惯。2.2 创建项目与跑通基础模板打开 Android Studio选择 File → New → New Project模板选 Empty Activity语言选 Java本教程用 Java 演示Kotlin 版逻辑完全一样只是语法不同Minimum SDK 用默认的 API 24 就可以。创建后系统会自动执行 Gradle 同步等右下角进度条走完项目结构就出来了。先别急着改代码直接点一次 Run把模板默认的 Hello World 跑起来。这一步非常重要它的目的是验证你的环境没问题。很多新手一上来就写代码结果模拟器没启动、Gradle 没同步完就误以为代码写错了。先跑通模板后面所有问题都容易定位得多。跑通之后你要认识一下项目里的几个关键文件MainActivity.java程序的入口负责加载布局和处理逻辑。activity_main.xml界面布局文件控件的摆放都写在这里。AndroidManifest.xml应用的配置文件所有 Activity 都要在这里注册。build.gradle依赖和编译配置。这几个文件在后续开发中每天都会接触不要求背下来但必须知道每个文件负责什么。2.3 理解 Android 项目的基本运行流程Activity 是 Android 应用的“页面”。MainActivity 继承自 AppCompatActivity它的 onCreate 方法里调用 setContentView 来加载布局。简单说就是代码通过 R.layout.activity_main 找到布局文件Android 系统把它解析成界面然后 show 出来。所有你想在界面上操作的东西比如输入框、按钮、文本都需要在布局里定义 id然后在 Java 代码里通过 findViewById 找到这个控件的对象才能操作它。这个“布局定义 → 代码查找 → 事件操作”的模式是 Android 开发的核心套路这个项目会把整个过程完整走一遍。AndroidManifest.xml 里要注意一点每新增一个 Activity都要在里面加一条 注册代码。初学者最容易漏掉这一步结果运行到跳转时直接闪退报 ActivityNotFoundException。3. 注册界面布局手写 activity_main.xml3.1 表单字段设计与控件选型个人信息注册我用到了下面这些字段姓名、年龄、性别、联系电话、个人简介。为什么选这几个因为它们的类型正好覆盖了最常见的输入场景姓名单行普通文本。年龄纯数字输入。性别单选按钮两个选项。电话手机号格式数字键盘。简介多行文本。这几个字段都不涉及运行时权限。你要是想加个头像上传就需要申请相册权限那复杂度就上来了不适合作为第一个练手项目。字段确定后控件的选择就顺理成章了EditText 负责文本输入RadioGroup 套两个 RadioButton 负责性别单选Button 负责触发注册。你可能想问为什么不直接用 DatePicker 选生日、用 Switch 做开关不是不行而是这个 demo 的定位就是尽量简单让你先抓住布局和逻辑的主线。等这部分熟练了想怎么换控件都行。3.2 activity_main.xml 完整代码下面这份布局可以直接复制到你的项目里替换 activity_main.xml 的默认内容。根布局用 LinearLayout设置成垂直排列这样每个输入项会从上到下依次摆放最直观也最好理解。?xml version1.0 encodingutf-8? LinearLayout xmlns:androidhttp://schemas.android.com/apk/res/android android:layout_widthmatch_parent android:layout_heightmatch_parent android:orientationvertical android:padding20dp TextView android:layout_widthwrap_content android:layout_heightwrap_content android:text姓名 android:textSize16sp / EditText android:idid/et_name android:layout_widthmatch_parent android:layout_heightwrap_content android:hint请输入姓名 android:inputTypetextPersonName android:maxLength20 / TextView android:layout_widthwrap_content android:layout_heightwrap_content android:text年龄 android:textSize16sp android:layout_marginTop12dp / EditText android:idid/et_age android:layout_widthmatch_parent android:layout_heightwrap_content android:hint请输入年龄 android:inputTypenumber android:maxLength3 / TextView android:layout_widthwrap_content android:layout_heightwrap_content android:text性别 android:textSize16sp android:layout_marginTop12dp / RadioGroup android:idid/rg_gender android:layout_widthmatch_parent android:layout_heightwrap_content android:orientationhorizontal RadioButton android:idid/rb_male android:layout_widthwrap_content android:layout_heightwrap_content android:text男 / RadioButton android:idid/rb_female android:layout_widthwrap_content android:layout_heightwrap_content android:text女 android:layout_marginStart20dp / /RadioGroup TextView android:layout_widthwrap_content android:layout_heightwrap_content android:text联系电话 android:textSize16sp android:layout_marginTop12dp / EditText android:idid/et_phone android:layout_widthmatch_parent android:layout_heightwrap_content android:hint请输入11位手机号 android:inputTypephone android:maxLength11 / TextView android:layout_widthwrap_content android:layout_heightwrap_content android:text个人简介 android:textSize16sp android:layout_marginTop12dp / EditText android:idid/et_intro android:layout_widthmatch_parent android:layout_heightwrap_content android:hint一句话介绍自己 android:inputTypetextMultiLine android:minLines3 android:gravitytop / Button android:idid/btn_register android:layout_widthmatch_parent android:layout_heightwrap_content android:text注 册 android:layout_marginTop24dp / /LinearLayout这里每个输入框都设置了 hint也就是灰色的提示文字。inputType 这个属性很关键年龄设成 number手机上会直接弹数字键盘电话设成 phone弹出的就是拨号键盘简介设成 textMultiLine支持换行。maxLength 能限制输入长度防止年龄填 1000 这种离谱数据。3.3 布局中的几个实用小技巧第一颜色和尺寸尽量统一定义。在 values/colors.xml 里加几个常用颜色比如主题色、提示文字色、背景色后面想改整体风格改一处就行不用每个布局翻一遍。第二RadioGroup 里的性别如果觉得横排太挤可以改成 vertical或者调整 margin 控制间距这个看屏幕宽度。第三EditText 默认的样式是底部一条横线如果你想要圆角输入框可以在 background 里指定一个 shape 的 drawable效果会好看很多。第四布局右侧的 Preview 面板可以切换不同尺寸的虚拟设备预览写界面时多看看预览能省不少在真机上反复安装调试的时间。这些小技巧不是这个项目的必选项但都是写实际项目时高频用到的东西。新手早期养成好习惯后面写复杂页面会省心很多。4. 核心逻辑实现数据校验、保存与页面跳转4.1 获取控件对象与点击事件布局写完之后接下来就是 MainActivity 里的事情。你要先通过 findViewById 拿到每个控件的对象再用等号左侧的变量去持有它。这一步类似于你给控件起了一个能在 Java 代码里使用的名字之后调用它的方法才不会报错。按钮的点击事件我用的是匿名内部类写法这是最直观的方式btnRegister.setOnClickListener(new View.OnClickListener() { Override public void onClick(View v) { register(); } });把注册逻辑单独抽成一个 register 方法好处是代码干净以后想加提示语、做埋点只需要改一个地方。点击事件跑在 Android 的主线程如果你在 onClick 里做了耗时操作比如访问网络、大量计算界面会卡住甚至触发 ANR。这个项目里全是读输入、写文件这类轻量操作所以没问题但你要有这个意识耗时的操作不能直接放在按钮回调里。4.2 输入校验判空、格式与正则表达式注册逻辑的第一步是校验。这一步为什么重要因为用户数据是不可信的。用户可能什么都不填直接点注册也可能在年龄框里输入字母或者在电话框里输入 9 位数。如果你不做限制脏数据一旦进入存储后面的业务逻辑会很头疼。我写的校验规则是这样姓名去掉首尾空格后不能为空长度 2 到 20 个字。年龄不能为空必须是纯数字且范围在 1 到 120 之间。电话不能为空用正则校验必须是 1 开头的 11 位手机号。性别必须至少选中一个选项。简介不能为空但长度可以放宽5 到 100 个字都行。核心代码大致是这样private void register() { String name etName.getText().toString().trim(); String ageText etAge.getText().toString().trim(); String phone etPhone.getText().toString().trim(); String intro etIntro.getText().toString().trim(); if (TextUtils.isEmpty(name)) { etName.setError(姓名不能为空); etName.requestFocus(); return; } if (TextUtils.isEmpty(ageText)) { etAge.setError(年龄不能为空); etAge.requestFocus(); return; } int age 0; try { age Integer.parseInt(ageText); } catch (NumberFormatException e) { etAge.setError(年龄必须是数字); etAge.requestFocus(); return; } if (age 0 || age 120) { etAge.setError(请输入1~120之间的年龄); etAge.requestFocus(); return; } if (TextUtils.isEmpty(phone)) { etPhone.setError(联系电话不能为空); etPhone.requestFocus(); return; } String phoneRegex ^1[3-9]\\d{9}$; if (!Pattern.matches(phoneRegex, phone)) { etPhone.setError(请输入正确的11位手机号); etPhone.requestFocus(); return; } int checkedId rgGender.getCheckedRadioButtonId(); if (checkedId -1) { Toast.makeText(this, 请选择性别, Toast.LENGTH_SHORT).show(); return; } String gender checkedId R.id.rb_male ? 男 : 女; String selectedGender gender; if (TextUtils.isEmpty(intro)) { etIntro.setError(个人简介不能为空); etIntro.requestFocus(); return; } saveUserInfo(name, age, selectedGender, phone, intro); }这里有一个很实用的小细节校验失败时用 setError 而不是 Toast。setError 会在输入框下方标红显示错误信息同时配合 requestFocus 把光标定位到出错的输入框用户一眼就知道哪里有问题。这个体验比弹一个 Toast 然后消失友好得多。正则表达式^1[3-9]\\d{9}$可能对新手有点陌生。简单拆解一下^ 表示开头1 是第一位数字必须是 1[3-9] 表示第二位是 3 到 9 中的任意一个数字\d{9} 表示后面还有 9 位数字$ 表示结尾。合起来就是 1 开头、总长度 11 位的手机号。正则很强大但不需要背用的时候查一下就行。4.3 使用 SharedPreferences 保存注册信息校验通过后就该存数据了。SharedPreferences 的使用方式非常简单三步走第一步获取 SharedPreferences 对象SharedPreferences prefs getSharedPreferences(user_info, MODE_PRIVATE);第一个参数 user_info 是文件名第二个参数 MODE_PRIVATE 表示只有当前应用能访问这个文件。第二步保存数据SharedPreferences.Editor editor prefs.edit(); editor.putString(name, name); editor.putInt(age, age); editor.putString(gender, gender); editor.putString(phone, phone); editor.putString(intro, intro); editor.apply();第三步读取数据String name prefs.getString(name, ); int age prefs.getInt(age, -1);这里有两个地方要特别说明。一个是 apply 和 commit 的区别。commit 是同步写入会直接操作磁盘返回 boolean 告诉你是否成功apply 是异步写入先把数据更新到内存再在后台写入磁盘速度快很多。Android 官方推荐优先用 apply。另一个是 getString 的第二个参数是默认值如果文件里没有这个 key就返回这个默认值这样做可以避免返回 null 导致空指针。你可以在模拟器的 Device File Explorer 里找到 /data/data/你的包名/shared_prefs/user_info.xml 这个文件点开看一眼会发现就是普通 XML里面一个个 标签存着你的注册信息。理解了这一点SharedPreferences 的底层逻辑就完全透明了。不过要记住它的限制同一份 prefs 文件里同一个 key 再次写入会覆盖旧值。也就是说这个简单版注册功能只能存一份用户信息。想要支持多个用户要么用不同的 key要么就得上数据库了。4.4 跳转结果页并显示数据数据保存好之后下一步就是跳转到结果页。这里有两种传值方式我在代码里都标出来了。方式一是用 Intent 直接携带数据Intent intent new Intent(MainActivity.this, ResultActivity.class); intent.putExtra(name, name); intent.putExtra(age, age); intent.putExtra(gender, gender); intent.putExtra(phone, phone); intent.putExtra(intro, intro); startActivity(intent);方式二是 ResultActivity 自己去 SharedPreferences 里读数据。因为刚才已经存好了直接在 ResultActivity 的 onCreate 里重新 get 一遍就行。这个案例我更推荐方式二因为数据已经持久化结果页自己读就好逻辑上更干净。但 Intent 传值在 Android 开发里太常用了所以我也会在示例代码里保留一份 putExtra 的写法你以后做列表项点击跳转详情页时会频繁用到。ResultActivity 逻辑很简单在 onCreate 里 findViewById 拿到展示文本的 TextView然后把 prefs 里读出来的数据拼成一段文字 setText 上去。记得在 AndroidManifest.xml 里注册这个 Activity这是 Android 开发最容易踩的坑之一。5. 实际跑通的完整代码与运行效果5.1 MainActivity 完整 Java 代码下面这份代码可以直接替换你创建的 MainActivity.java注意包名和项目保持一致即可。package com.example.yourapp; import android.content.SharedPreferences; import android.os.Bundle; import android.text.TextUtils; import android.widget.Button; import android.widget.EditText; import android.widget.RadioGroup; import android.widget.Toast; import androidx.appcompat.app.AppCompatActivity; import java.util.regex.Pattern; public class MainActivity extends AppCompatActivity { private EditText etName, etAge, etPhone, etIntro; private RadioGroup rgGender; private Button btnRegister; Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); etName findViewById(R.id.et_name); etAge findViewById(R.id.et_age); etPhone findViewById(R.id.et_phone); etIntro findViewById(R.id.et_intro); rgGender findViewById(R.id.rg_gender); btnRegister findViewById(R.id.btn_register); btnRegister.setOnClickListener(v - register()); } private void register() { String name etName.getText().toString().trim(); String ageText etAge.getText().toString().trim(); String phone etPhone.getText().toString().trim(); String intro etIntro.getText().toString().trim(); if (TextUtils.isEmpty(name)) { etName.setError(姓名不能为空); etName.requestFocus(); return; } if (TextUtils.isEmpty(ageText)) { etAge.setError(年龄不能为空); etAge.requestFocus(); return; } int age; try { age Integer.parseInt(ageText); } catch (NumberFormatException e) { etAge.setError(年龄必须是数字); etAge.requestFocus(); return; } if (age 0 || age 120) { etAge.setError(请输入1~120之间的年龄); etAge.requestFocus(); return; } if (TextUtils.isEmpty(phone)) { etPhone.setError(联系电话不能为空); etPhone.requestFocus(); return; } String phoneRegex ^1[3-9]\\d{9}$; if (!Pattern.matches(phoneRegex, phone)) { etPhone.setError(请输入正确的11位手机号); etPhone.requestFocus(); return; } int checkedId rgGender.getCheckedRadioButtonId(); if (checkedId -1) { Toast.makeText(this, 请选择性别, Toast.LENGTH_SHORT).show(); return; } String gender (checkedId R.id.rb_male) ? 男 : 女; if (TextUtils.isEmpty(intro)) { etIntro.setError(个人简介不能为空); etIntro.requestFocus(); return; } saveUserInfo(name, age, gender, phone, intro); Toast.makeText(this, 注册成功, Toast.LENGTH_SHORT).show(); // 方式一Intent 传值 // Intent intent new Intent(MainActivity.this, ResultActivity.class); // intent.putExtra(name, name); // intent.putExtra(age, age); // intent.putExtra(gender, gender); // intent.putExtra(phone, phone); // intent.putExtra(intro, intro); // startActivity(intent); // 方式二ResultActivity 直接读取 SharedPreferences startActivity(new Intent(MainActivity.this, ResultActivity.class)); } private void saveUserInfo(String name, int age, String gender, String phone, String intro) { SharedPreferences prefs getSharedPreferences(user_info, MODE_PRIVATE); SharedPreferences.Editor editor prefs.edit(); editor.putString(name, name); editor.putInt(age, age); editor.putString(gender, gender); editor.putString(phone, phone); editor.putString(intro, intro); editor.apply(); } }注意这段代码用了 lambda 表达式简化点击事件如果你的项目默认 Java 版本支持Android Studio 会自动编译通过。如果不支持改成匿名内部类的写法即可效果一样。5.2 ResultActivity 布局与完整代码先建一个空 Activity名字叫 ResultActivity布局文件这里直接用一个 ScrollView 包一个 TextView避免简介太长时超出屏幕。activity_result.xml 代码如下?xml version1.0 encodingutf-8? 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:padding20dp TextView android:idid/tv_result android:layout_widthwrap_content android:layout_heightwrap_content android:textSize18sp android:lineSpacingExtra8dp / /LinearLayout /ScrollViewResultActivity.java 代码如下package com.example.yourapp; import android.content.SharedPreferences; import android.os.Bundle; import android.widget.TextView; import androidx.appcompat.app.AppCompatActivity; public class ResultActivity extends AppCompatActivity { Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_result); TextView tvResult findViewById(R.id.tv_result); // 方式一从 Intent 中读取如果 MainActivity 用 putExtra 传值 // String name getIntent().getStringExtra(name); // int age getIntent().getIntExtra(age, -1); // String gender getIntent().getStringExtra(gender); // String phone getIntent().getStringExtra(phone); // String intro getIntent().getStringExtra(intro); // 方式二从 SharedPreferences 中读取 SharedPreferences prefs getSharedPreferences(user_info, MODE_PRIVATE); String name prefs.getString(name, ); int age prefs.getInt(age, -1); String gender prefs.getString(gender, ); String phone prefs.getString(phone, ); String intro prefs.getString(intro, ); tvResult.setText(注册信息如下\n\n 姓名 name \n 年龄 age \n 性别 gender \n 联系电话 phone \n 个人简介 intro); } }别忘了在 AndroidManifest.xml 里加上activity android:name.ResultActivity /放在 节点下的 MainActivity 注册信息旁边即可。5.3 运行流程与预期效果这个项目跑通后的操作流程是这样的打开 App看到注册表单。什么都不填直接点注册姓名输入框下方会标红提示“姓名不能为空”。姓名填了年龄填 abc点注册年龄输入框下方提示“年龄必须是数字”。表单全部填对点击注册Toast 弹出“注册成功”界面自动跳到 ResultActivity。ResultActivity 显示完整的注册信息。你可以试着重启 App再次进入 ResultActivity可以从 MainActivity 直接点注册进去会发现注册信息依然在这就是持久化的意义。如果数据只是存在内存里App 一关就没了用了 SharedPreferences数据已经落到了磁盘上的 XML 文件里不会丢。5.4 无数据库版与后续扩展方向对比把这个无数据库版跑通后你可以用这张表来理解它和数据库方案的区别方案存储位置适用场景优点缺点SharedPreferencesshared_prefs/XML 文件键值对、用户偏好、单条注册信息代码简单无需额外类API 友好不支持条件查询多用户数据管理麻烦SQLite应用私有数据库文件结构化数据、增删改查、复杂查询系统自带支持 SQL轻量需要写辅助类Cursor 操作略繁琐Room数据库文件基于 SQLite生产级本地数据存储编译期校验 SQL支持 LiveData/Flow代码简洁需要学习注解引入依赖较多从这个项目往下扩展方向很清晰把 SharedPreferences 换成 SQLite做一个真正的注册表支持多个用户。加一个登录页让用户输入注册时的姓名和电话来验证身份。在 ResultActivity 里加一个“返回修改”按钮回填表单。把注册信息展示成一个列表这就涉及 RecyclerView 了。我个人建议你按这个顺序来先搞定无数据库版然后把存储换成 SQLite再加一个登录验证页面。每一步都是在前一步的基础上加一点新东西不会一次性引入太多概念。6. 新手最容易踩的坑与排查技巧6.1 常见问题速查表这个项目虽然简单但新手实际运行时会遇到不少问题。我把最常见的几个整理成了表格方便你对照排查。现象可能原因解决方法点击注册按钮后闪退ResultActivity 没有在 AndroidManifest 中注册在 application 节点下加activity android:name.ResultActivity /点击按钮没反应按钮 id 绑定错误或 findViewById 写错检查 activity_main.xml 中按钮的 id 和代码中 R.id 是否一致闪退并报空指针某个控件变量没有初始化就直接调用方法逐个检查 findViewById 是否都写在 onCreate 里且 id 正确年龄输入框还能输入字母inputType 没有生效可能是布局缓存检查 XML 里是否写了android:inputTypenumber清理重建项目性别不选也能注册没有判断 RadioGroup 的选中状态用rgGender.getCheckedRadioButtonId() -1做拦截数据保存后重启读取不到key 名称不一致或用了 commit 但没同步完检查 putString/getString 的 key 是否完全一致模拟器启动极慢虚拟化未开启或内存不足开启 HAXM/Hyper-V或改用真机调试Gradle 同步失败网络原因或镜像源问题切换国内镜像源或等网络稳定后重试排查问题有一个通用的心法不要盯着报错日志从头看到尾直接看最后一行“Caused by”或“Error”然后复制这行内容去搜效率高得多。Android Studio 的 Logcat 下方有过滤框可以按包名过滤能帮你快速筛掉系统日志。6.2 几个提高开发效率的实操心得最后分享几个我实际开发中验证过的心得。第一调试时多用 Log.d 而不是 Toast。Toast 会弹窗打断操作而且不能打印变量的细节Log.d 只往 Logcat 里写一行不干扰界面你可以在代码里想看的位置打日志跑完再统一删除。这个习惯越早养成越好。第二布局文件改完后先在 Preview 面板看效果再跑模拟器。模拟器每次启动和安装 APK 都要时间预览几乎是秒开的能帮你快速调整间距、字体、颜色这些细节。第三写代码前先在纸上画一下草图和字段列表。这个项目比较简单可能体会不深但养成习惯后做复杂项目时你会发现画图的时间远小于改代码的时间。第四遇到报错先读 Logcat 的红色部分特别是带自己包名的错误。新手容易看到一大坨日志就慌其实大部分系统日志是可以忽略的你只要关心自己代码相关的部分即可。第五善用断点调试。在 register 方法里打一个断点用 Debug 模式运行可以看到 name、age、phone 这些变量在每一步的值比死盯代码猜要强得多。我见过很多同学不会用断点遇到问题就加打印、猜原因其实 Android Studio 的调试器早就把答案摆在那里了。这个无数据库版的注册项目是我认为最适合 Android 新手练手的第一个“有业务感”的 demo。它麻雀虽小但五脏俱全。跑通它之后你对“界面 - 事件 - 存储 - 跳转”这条 Android 开发核心链路会有非常具体的感知。下一步你可以试着给它加一个登录页用来读取已经注册的信息或者把存储层换成 SQLite体验一下数据库带来的更多可能性。按这个顺序一步步来你会发现 Android 开发其实没那么难。本文还有配套的精品资源点击获取
返回列表