
简介这是一份面向Android开发初学者的入门级实战资源基于Android Studio与Java语言实现一个不含数据库的简单个人信息注册小应用。功能覆盖用户名与密码输入、单选框选择性别、下拉框选择地址、复选框勾选爱好点击按钮提交后跳转结果页展示全部填写内容并对输入框为空的情况给出提示结果页还可返回首页适合刚接触移动应用开发、想练手界面控件与页面跳转的读者。压缩包共495个文件约10.27MB以xml布局、json配置、flat缓存、webp图片、dex与class字节码、java源码及gradle构建脚本为主完整保留了工程结构与构建产物便于直接导入运行和对照学习。目前已有846人学习下载可作为课堂示例或自学练手项目帮助读者快速理解Activity跳转、控件取值与简单表单校验的实现思路。1. 从零拆一个无数据库注册页Android Studio 里最值得先跑通的那类小工程很多人第一次打开 Android Studio面对 Gradle 同步、SDK 下载、模拟器镜像这一堆东西还没写一行业务代码就先被环境劝退了。而「个人信息注册」这个场景恰好是破局点它足够小小到不需要数据库、不需要网络请求、不需要第三方框架一个 Activity 加一个布局文件就能跑起来但它又足够完整完整到把 Android 开发最核心的几件事——控件声明、输入校验、点击事件、页面跳转、数据传递——全都串了一遍。这份资源就是围绕这个场景展开的用 Java 语言在 Android Studio 里实现一个纯本地的注册表单输入姓名、手机号、密码点击提交后做基本校验并跳转展示结果。它适合刚装好 Android Studio 想找个能跑通的小项目练手的人也适合需要给学生演示「一个 App 最小闭环长什么样」的讲师。没有数据库意味着你不用碰 SQLite、Room 或任何持久化方案所有数据只在内存和 Intent 里流转跑完就丢反而让注意力能集中在 UI 和逻辑本身。2. 环境与工程结构把 Android Studio 的坑先填平2.1 新建工程时的几个关键选择打开 Android Studio 后走New Project模板选Empty Views Activity老版本叫Empty Activity这一步别选成 Compose 模板否则生成的是 Kotlin Jetpack Compose 的代码结构跟这份资源的 Java XML 路线对不上。语言选 JavaMinimum SDK 建议选API 24: Android 7.0这个版本覆盖了绝大多数在用设备又不会因为版本太低导致部分 API 不可用。Build configuration language 选 Groovy DSL 还是 Kotlin DSL 都行但如果你看的教程里build.gradle写法跟你的对不上多半就是这里选岔了。工程创建完成后左侧项目视图切到Android模式你会看到几个核心目录。app/src/main/java/下放 Java 代码app/src/main/res/layout/下放布局 XMLapp/src/main/res/values/下放字符串、颜色、主题这些资源定义app/src/main/AndroidManifest.xml是应用清单声明 Activity 和权限。这个项目不需要任何权限所以清单文件里不用加uses-permission。提示如果创建工程时卡在Downloading Gradle或Unable to access Android SDK add-on list通常是网络问题。Gradle 分发包可以在gradle-wrapper.properties里把distributionUrl换成国内镜像地址SDK 则在Settings → Appearance Behavior → System Settings → HTTP Proxy里配置镜像源。这一步不解决后面所有操作都无从谈起。2.2 布局文件用 LinearLayout 搭出注册表单在res/layout/下新建activity_register.xml用垂直方向的LinearLayout作为根容器里面依次放标题、姓名输入框、手机号输入框、密码输入框、提交按钮。每个EditText都要给android:id这是后面在 Java 里通过findViewById拿到控件的唯一凭据。?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:padding24dp TextView android:layout_widthwrap_content android:layout_heightwrap_content android:text个人信息注册 android:textSize24sp android:textStylebold android:layout_gravitycenter_horizontal android:layout_marginBottom32dp / EditText android:idid/et_name android:layout_widthmatch_parent android:layout_heightwrap_content android:hint请输入姓名 android:inputTypetextPersonName android:maxLength20 / EditText android:idid/et_phone android:layout_widthmatch_parent android:layout_heightwrap_content android:hint请输入手机号 android:inputTypephone android:maxLength11 android:layout_marginTop16dp / EditText android:idid/et_password android:layout_widthmatch_parent android:layout_heightwrap_content android:hint请输入密码 android:inputTypetextPassword android:maxLength16 android:layout_marginTop16dp / Button android:idid/btn_submit android:layout_widthmatch_parent android:layout_heightwrap_content android:text提交注册 android:layout_marginTop32dp / /LinearLayout这段布局里几个参数值得说清楚。inputTypetextPassword让密码框自动显示为圆点不需要你手动处理掩码inputTypephone会弹出数字键盘减少用户输错概率maxLength限制输入长度姓名 20 字符、手机号 11 位、密码 16 位这是前端校验的第一道防线。layout_marginTop控制控件间距比用Space控件更直接。layout_gravitycenter_horizontal只作用于当前控件在父容器中的水平位置跟gravity控制内容对齐是两回事新手容易搞混。2.3 Activity 代码输入校验与页面跳转新建RegisterActivity.java继承AppCompatActivity在onCreate里绑定布局、获取控件引用、给按钮设置点击监听。点击事件里做三步取输入值、校验、跳转。package com.example.myregister; import android.content.Intent; import android.os.Bundle; import android.text.TextUtils; import android.widget.Button; import android.widget.EditText; import android.widget.Toast; import androidx.appcompat.app.AppCompatActivity; public class RegisterActivity extends AppCompatActivity { private EditText etName, etPhone, etPassword; Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_register); etName findViewById(R.id.et_name); etPhone findViewById(R.id.et_phone); etPassword findViewById(R.id.et_password); Button btnSubmit findViewById(R.id.btn_submit); btnSubmit.setOnClickListener(v - { String name etName.getText().toString().trim(); String phone etPhone.getText().toString().trim(); String password etPassword.getText().toString().trim(); if (TextUtils.isEmpty(name)) { Toast.makeText(this, 姓名不能为空, Toast.LENGTH_SHORT).show(); return; } if (phone.length() ! 11 || !phone.startsWith(1)) { Toast.makeText(this, 请输入正确的手机号, Toast.LENGTH_SHORT).show(); return; } if (password.length() 6) { Toast.makeText(this, 密码至少6位, Toast.LENGTH_SHORT).show(); return; } Intent intent new Intent(RegisterActivity.this, ResultActivity.class); intent.putExtra(name, name); intent.putExtra(phone, phone); startActivity(intent); }); } }getText().toString().trim()里的trim()是血泪经验用户输入时很容易在末尾多打一个空格不处理的话「张三 」和「张三」在校验逻辑里就是两个不同的值。TextUtils.isEmpty同时判断 null 和空字符串比str null || str.equals()简洁。手机号校验这里只做了长度和首位判断没有用正则因为无数据库版本不需要那么严格但如果你要扩展正则是更稳妥的做法。Intent传值时 key 用字符串常量接收方通过同一个 key 取值这是 Activity 间通信最基本的方式。2.4 结果页与清单注册再建一个ResultActivity.java和对应的activity_result.xml布局里放两个 TextView 显示姓名和手机号。在onCreate里通过getIntent().getStringExtra(name)取值并设置到 TextView 上。public class ResultActivity extends AppCompatActivity { Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_result); String name getIntent().getStringExtra(name); String phone getIntent().getStringExtra(phone); TextView tvName findViewById(R.id.tv_name); TextView tvPhone findViewById(R.id.tv_phone); tvName.setText(姓名 name); tvPhone.setText(手机号 phone); } }两个 Activity 都必须在AndroidManifest.xml里声明否则启动时直接崩。如果RegisterActivity是启动页它的intent-filter里要包含MAIN和LAUNCHERResultActivity只需要一个普通的activity标签。application ... activity android:name.RegisterActivity android:exportedtrue intent-filter action android:nameandroid.intent.action.MAIN / category android:nameandroid.intent.category.LAUNCHER / /intent-filter /activity activity android:name.ResultActivity android:exportedfalse / /applicationandroid:exported这个属性在 Android 12 以后是强制要求的启动页设为true内部页面设为false不写或写错会直接编译报错。这是近几年 Android 版本升级里最容易让老教程翻车的地方之一。3. 避坑与排查无数据库注册页最容易翻车的五个点3.1 点击按钮没反应日志里也没有报错现象是 App 正常运行按钮能点但没有任何弹窗或跳转。原因通常是findViewById拿到的控件为 null或者setOnClickListener根本没执行到。检查setContentView里传入的布局 ID 是否跟实际文件名一致检查findViewById的 ID 是否跟 XML 里的android:id完全匹配——大小写、下划线都不能差。还有一种可能是按钮被其他控件遮挡了在布局预览里看一下层级。3.2 跳转后 ResultActivity 显示 null现象是页面跳过去了但 TextView 显示「姓名null」。原因是putExtra的 key 和getStringExtra的 key 不一致或者数据类型对不上。putExtra(name, name)存的是 String取的时候就必须用getStringExtra(name)不能用getIntExtra。建议把 key 定义成public static final String常量放在一个公共类里两边引用同一个常量从根上杜绝拼写错误。3.3 输入中文后校验逻辑失效现象是输入中文姓名后isEmpty判断通过但后续处理异常。原因是部分输入法在中文状态下会插入全角空格或不可见字符trim()只能去掉半角空格。解决方式是在校验前先用replaceAll(\\s, )去掉所有空白字符或者用name.replace(\u3000, ).trim()专门处理全角空格。这个坑在真机上比模拟器更容易出现。3.4 模拟器上正常真机上按钮被键盘挡住现象是在 Android Studio 自带模拟器里布局正常装到真机上后软键盘弹出时把提交按钮遮住了。原因是模拟器屏幕比例和真机不同且真机键盘高度差异很大。解决方式是在AndroidManifest.xml对应的 Activity 里加android:windowSoftInputModeadjustResize让布局在键盘弹出时自动调整大小或者把根布局换成ScrollView保证内容始终可滚动到。3.5 Gradle 同步失败导致 R 文件找不到现象是代码里所有R.id.xxx标红提示Cannot resolve symbol R。原因通常是 Gradle 同步没成功资源文件没有被正确编译。先看 Build 窗口的报错信息如果是 SDK 路径问题就去local.properties里检查sdk.dir如果是依赖下载失败就检查网络和镜像配置。实在不行走Build → Clean Project再Rebuild Project大部分 R 文件问题都能靠这一步解决。4. 进阶技巧把校验逻辑抽出来让代码能复用4.1 用工具类封装校验规则上面把校验逻辑全写在点击事件里项目小的时候没问题但一旦要加「确认密码」「邮箱」这些字段onClick里就会堆成一座山。更合理的做法是抽一个Validator工具类每个校验方法只做一件事返回 boolean 或错误信息。public class Validator { public static boolean isValidName(String name) { return name ! null !name.replaceAll(\\s, ).isEmpty(); } public static boolean isValidPhone(String phone) { if (phone null || phone.length() ! 11) return false; if (!phone.startsWith(1)) return false; for (char c : phone.toCharArray()) { if (!Character.isDigit(c)) return false; } return true; } public static boolean isValidPassword(String password) { return password ! null password.length() 6 password.length() 16; } }这样点击事件里就变成三个if调用每个if只关心一个字段新增字段时加一个方法就行不用动原有逻辑。isValidPhone里逐字符判断是否为数字比正则更直观性能也更好适合这种固定长度的场景。4.2 用 startActivityForResult 或 ActivityResultLauncher 回传数据目前 ResultActivity 只是被动接收数据如果要做「返回修改」功能就需要 ResultActivity 把修改后的数据回传给 RegisterActivity。老写法是startActivityForResultonActivityResult但这套 API 已经废弃新项目应该用ActivityResultLauncher。private ActivityResultLauncherIntent launcher registerForActivityResult( new ActivityResultContracts.StartActivityForResult(), result - { if (result.getResultCode() RESULT_OK result.getData() ! null) { String newName result.getData().getStringExtra(name); etName.setText(newName); } } );在 ResultActivity 里通过setResult(RESULT_OK, intent)回传然后finish()关闭自己。这套机制在无数据库场景下特别有用因为数据不落盘页面间传递就是唯一的状态管理手段。4.3 验证清单跑通之后逐条对一遍检查项预期结果不通过时看哪里空姓名提交弹 Toast「姓名不能为空」isValidName逻辑手机号 10 位弹 Toast「请输入正确的手机号」isValidPhone长度判断手机号含字母弹 Toast 同上逐字符判断分支密码 5 位弹 Toast「密码至少6位」isValidPassword长度全部合法跳转并正确显示姓名手机号Intent key 是否一致真机键盘弹出按钮不被遮挡windowSoftInputMode这张表建议每改一次校验逻辑就跑一遍尤其是调整了maxLength或inputType之后很容易出现「输入被截断导致校验永远不通过」的玄学问题。4.4 从这个小工程往外延伸的方向跑通之后这个工程可以往几个方向长。一是加RadioGroup选性别、加Spinner选城市练的是选择类控件的取值二是把数据存到SharedPreferences练的是最简单的本地持久化比数据库轻量得多三是把校验规则换成正则表达式练的是Pattern和Matcher的用法。但不管往哪延伸核心闭环始终是「取输入 → 校验 → 反馈或跳转」这个模式在 Android 开发里会反复出现。从那以后我每次新建工程都会先把AndroidManifest.xml里的exported属性和windowSoftInputMode检查一遍再开始写业务代码这两个地方翻车过一次就够记一辈子。希望帮到你。本文还有配套的精品资源点击获取