Android三页面跳转实战:Activity生命周期与Intent数据传递

发布时间:2026/9/16 14:11:37
Android三页面跳转实战:Activity生命周期与Intent数据传递 简介这是一份基于Android Studio开发的QQ风格社交应用入门案例面向移动应用开发初学者及课程设计、大作业场景。项目围绕注册、登录、好友列表三大核心界面完整展示Activity间数据传递与页面跳转逻辑注册时输入的账号密码可跨页面传至登录界面登录成功后用户名同步带至好友列表好友列表含头像与消息内容展示贴近真实IM应用交互。代码附详细注释便于理解Android基础组件与Intent传参机制。资源共544个文件压缩包12.32MB核心包含Java源码、xml布局与配置文件、Gradle构建脚本、APK安装包及图片素材xml/json覆盖界面布局与数据配置png/jpg为设计素材jar/dex为依赖与编译产物整体为可直接运行的完整Android工程。已有6437人学习下载适合参考完整工程、复现页面跳转效果或直接用于课程设计对应博客附运行演示截图可辅助核对各界面交互细节。1. 三个页面一条链路把这个Android基础案例拆开看很多人学Android动手做的第一个完整案例就是仿QQ的注册页、登录页、好友列表页三页跳转。它被当作基础案例不是没道理Activity生命周期、Intent跳转、布局和简单数据存储一趟全用上做完你就知道Android应用里页面怎么切、数据怎么带。链路本身很简单注册页填账号密码保存后回登录页校验通过进好友列表页。真正的坎在页面之外返回时数据怎么回传按返回键退到哪注册信息存哪。这几个点想清楚多页面应用基本就通了。适合刚装好Android Studio、能跑通Hello World的人也适合带新人的工程师当评审样板。下文顺序先UI再跳转然后数据保存最后验证。2. 先把三个页面布局搭出来注册页、登录页、好友列表页的XML写跳转之前先把三张布局文件落实。布局是页面的骨架控件id怎么命名直接决定后面findViewById会不会写错这一步值得慢一点。2.1 新建Activity还是新建Layout先规划文件再动手新建工程时模板默认生成MainActivity和activity_main.xml。做这个案例我一般不改MainActivity而是直接再建三个ActivityLoginActivity、RegisterActivity、FriendsActivity每个Activity各带一张布局文件。在包名右键选New→Activity→Empty Views Activity分别命名即可模板会自动生成对应的activity_xxx.xml并在AndroidManifest.xml里补注册信息。布局文件对应Activity核心控件职责activity_register.xmlRegisterActivityEditText×2、Button输入账号密码回传数据activity_login.xmlLoginActivityEditText×2、Button、TextView校验账号密码进入列表activity_friends.xmlFriendsActivityTextView、ListView展示当前用户和好友列表提示新建工程后首次Gradle Sync比较慢这是下载依赖的正常现象可以配镜像源加速想用中文界面就在Settings→Plugins里装Chinese Language Pack。两者都不影响本案例代码。2.2 activity_register.xml用LinearLayout写注册页注册页是三张里最简单的用竖直LinearLayout嵌套层级少初学者看着不晕。密码输入框一定要设inputTypetextPassword否则键盘上方会明文显示输入内容。?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 / !-- 账号输入框maxLines1 防止实体键盘换行 -- EditText android:idid/et_register_account android:layout_widthmatch_parent android:layout_heightwrap_content android:hint请输入账号 android:inputTypetext android:maxLines1 / !-- 密码框输入内容会被圆点遮盖 -- EditText android:idid/et_register_password android:layout_widthmatch_parent android:layout_heightwrap_content android:hint请输入密码 android:inputTypetextPassword android:maxLines1 / Button android:idid/btn_register android:layout_widthmatch_parent android:layout_heightwrap_content android:text注册并返回登录 / /LinearLayout根布局宽高用match_parent铺满屏幕padding24dp让控件不贴边。控件id用et_、btn_前缀区分类型第3章写跳转逻辑时能直接对上。想用ConstraintLayout也行但LinearLayout在这种纵向表单上更省代码也更好讲清楚weight的用法。2.3 登录页与好友列表页的布局多一个去注册入口登录页在注册页基础上加两样一个“没有账号去注册”的TextView留给第3章的Intent跳转一个登录按钮。好友列表页顶部放TextView显示“欢迎xxx”下面放ListView列表项先用系统自带的simple_list_item_1正式项目再换自定义item。!-- activity_friends.xml 关键部分 -- LinearLayout android:layout_widthmatch_parent android:layout_heightmatch_parent android:orientationvertical TextView android:idid/tv_welcome android:layout_widthmatch_parent android:layout_heightwrap_content android:padding16dp android:textSize18sp android:text欢迎 / !-- height0dp weight1 占满剩余空间 -- ListView android:idid/lv_friends android:layout_widthmatch_parent android:layout_height0dp android:layout_weight1 / /LinearLayoutListView的layout_height用0dp配合layout_weight1是LinearLayout里占满剩余空间的常用写法比写死数值更适应不同屏幕。到这一步三张界面就绪下一步解决三个页面怎么被正确注册、怎么跳。3. AndroidManifest注册与页面跳转显式Intent怎么把三个页面串起来界面只是静态骨架真正让注册、登录、好友列表三页动起来的是Intent。这一章把manifest注册和三种跳转写法一次说清。3.1 先改AndroidManifest.xmllauncher是谁、exported怎么设模板建出来的MainActivity默认是启动页。做这个案例时我一般删掉MainActivity和activity_main.xml把LoginActivity设为入口。打开AndroidManifest.xml确认三个Activity都有对应的节点并在LoginActivity上配MAIN和LAUNCHER的intent-filter。application android:allowBackuptrue android:iconmipmap/ic_launcher android:labelstring/app_name android:themestyle/Theme.AppCompat.Light.NoActionBar activity android:name.FriendsActivity / activity android:name.RegisterActivity / !-- 登录页作为启动入口 -- activity android:name.LoginActivity android:exportedtrue intent-filter action android:nameandroid.intent.action.MAIN / category android:nameandroid.intent.category.LAUNCHER / /intent-filter /activity /application从Android 12API 31开始声明了intent-filter的Activity必须写android:exportedtrue表示允许其他应用唤起launcher入口固定写trueRegisterActivity和FriendsActivity不对外暴露不写或写false都行。漏注册的典型症状是运行即闪退logcat里报ActivityNotFoundException第5章会专门说怎么看日志定位。3.2 登录页到好友列表页一句startActivity的事应用内两个页面之间的跳转用显式Intent写法是在构造时直接指定目标Activity的Class。登录按钮的点击事件里加这段// LoginActivity.java findViewById(R.id.btn_login).setOnClickListener(v - { // 显式Intent第一个参数是当前Context第二个是目标Activity Intent intent new Intent(LoginActivity.this, FriendsActivity.class); startActivity(intent); });startActivity调用后登录页进入onPause好友列表页依次走onCreate→onStart→onResume这就是Activity生命周期在跳转时的实际表现。这里必须想清楚一个点登录成功后要不要finish()。常见做法是finish因为登录页使命已结束不finish的话用户在好友列表页按返回键会退回登录页体验上是个bug。注意finish()要在startActivity之后调用先finish再startActivity在某些场景会出问题。3.3 注册页返回登录页setResult回传Activity Result API是新写法如果注册页只是回登录页直接startActivity就行。但注册成功后账号要回填到登录页的输入框这需要把数据带回。startActivityForResult加onActivityResult这套老写法已经过时AndroidX里推荐registerForActivityResult代码更直观也避免回调里持有Activity引用导致泄漏。RegisterActivity这边注册按钮把账号放进Intent然后setResult再finish// RegisterActivity.java public static final String KEY_ACCOUNT registered_account; EditText etAccount findViewById(R.id.et_register_account); EditText etPassword findViewById(R.id.et_register_password); findViewById(R.id.btn_register).setOnClickListener(v - { String account etAccount.getText().toString().trim(); saveAccount(account, etPassword.getText().toString().trim()); // 第4章展开 Intent result new Intent(); result.putExtra(KEY_ACCOUNT, account); setResult(RESULT_OK, result); finish(); // 结束注册页自动回到启动它的登录页 });LoginActivity这边先注册一个launcher再启动注册页// LoginActivity.java 成员变量 ActivityResultLauncherIntent registerLauncher registerForActivityResult( new ActivityResultContracts.StartActivityForResult(), result - { if (result.getResultCode() RESULT_OK result.getData() ! null) { String account result.getData().getStringExtra(RegisterActivity.KEY_ACCOUNT); etLoginAccount.setText(account); // 账号自动回填 } }); // 点击去注册时启动 registerLauncher.launch(new Intent(LoginActivity.this, RegisterActivity.class));回调里result.getData()就是setResult塞进去的那个IntentgetStringExtra的key必须和putExtra完全一致key写错会静默返回null界面表现是账号没回填这是跳转传参最常见的翻车点。三种跳转的场景区别如下表场景跳转方式数据方向登录→好友列表startActivity单程不带回登录→注册registerLauncher.launch单程去注册注册→登录setResult finish带回账号数据到这一步页面能跳了但登录页凭什么相信输入的账号密码是对的下一步把注册数据真正落盘。4. 注册数据存哪里SharedPreferences存账号密码与登录校验Android基础案例里存账号密码最常见也最省事的方案是SharedPreferences。它本质是一个XML文件存在应用私有目录下key-value结构MODE_PRIVATE下只有本应用能读。不需要引入数据库也不用处理SQLite版本迁移。4.1 用getSharedPreferences保存注册信息apply不卡UI在RegisterActivity的注册按钮回调里补上保存逻辑核心就四行// RegisterActivity.java private void saveAccount(String account, String password) { SharedPreferences sp getSharedPreferences(user_info, MODE_PRIVATE); sp.edit() .putString(account, account) .putString(password, password) .apply(); // 异步写盘不阻塞UI线程 }getSharedPreferences第一个参数是文件名第二个是访问模式。两个Activity读同一个文件必须用同一个文件名user_info很多人出现“注册能存、登录读不到”八成是文件名或key不一致。apply()异步落盘commit()同步落盘基础案例用apply()即可真在乎写入完成时机再改用commit()。提示SharedPreferences存的是明文真实项目的账号密码不会这么存通常会走加密或AccountManager。基础案例的重点是页面跳转和流程串联明文方案够用但要清楚这个边界。4.2 登录页校验先判空再比对错误用Toast提示登录点击逻辑分三步取输入、判空、比对。判空必须放在比对前面否则空字符串去equals已保存的值用户也看不到任何反馈会以为按钮坏了。// LoginActivity.java private void doLogin() { String inputAccount etLoginAccount.getText().toString().trim(); String inputPassword etLoginPassword.getText().toString().trim(); if (inputAccount.isEmpty() || inputPassword.isEmpty()) { Toast.makeText(this, 账号和密码不能为空, Toast.LENGTH_SHORT).show(); return; } SharedPreferences sp getSharedPreferences(user_info, MODE_PRIVATE); String savedAccount sp.getString(account, ); // 默认值防null String savedPassword sp.getString(password, ); if (savedAccount.equals(inputAccount) savedPassword.equals(inputPassword)) { Toast.makeText(this, 登录成功, Toast.LENGTH_SHORT).show(); startActivity(new Intent(LoginActivity.this, FriendsActivity.class)); finish(); // 防止返回键退回登录页 } else { Toast.makeText(this, 账号或密码错误, Toast.LENGTH_SHORT).show(); } }trim()去掉首尾空格用户在输入法里多敲一个空格也不会判错。sp.getString的第二个参数是默认值防止第一次运行没注册时返回null——null.equals(inputAccount)会直接抛NullPointerException这就是很多人“没注册直接点登录闪退”的原因。登录成功后的finish()和上一章说的是同一个原则登录页的使命结束不该再让用户退回来。4.3 新手最常踩的三个坑取值时机、key不一致、点击没反应现象原因处理方式注册后登录永远报密码错误两个Activity里getSharedPreferences文件名不一致或key拼写不同统一文件名user_infokey统一为account/password没注册直接登录闪退getString默认值没写返回null后调equals默认值写判空提前点登录按钮完全没反应按钮没setOnClickListener或回调里return了但没Toast先检查监听器是否绑定判空分支必须有提示第三个坑再补充一句如果按钮绑了监听器仍无反应优先看XML里Button是不是被其他View遮住了常见的是根布局里某个控件把按钮盖住。真机调试时打开开发者选项里的“显示布局边界”能直接看出来。注册数据落盘、登录校验通过链路只剩最后一段把登录的用户名带进好友列表页并验证全流程。5. 把用户名带进好友列表页并验证整条跳转链路5.1 Intent Extra传用户名没取到给默认值登录成功后启动FriendsActivity在startActivity前加一行putExtraIntent intent new Intent(LoginActivity.this, FriendsActivity.class); intent.putExtra(username, inputAccount); // 把账号作为用户名传递 startActivity(intent);FriendsActivity里取数据时getStringExtra在key不存在时会返回null页面就会显示“欢迎null”。稳妥写法是判断后给默认值String username getIntent().getStringExtra(username); tvWelcome.setText(欢迎 (username ! null ? username : 游客));5.2 好友列表用ListView三行代码出数据基础案例里ListView配ArrayAdapter是最短路径Adapter是ListView和数据之间的桥梁String[] friends {张伟, 李娜, 王强, 赵敏}; ArrayAdapterString adapter new ArrayAdapter(this, android.R.layout.simple_list_item_1, friends); ((ListView) findViewById(R.id.lv_friends)).setAdapter(adapter);android.R.layout.simple_list_item_1是系统内置的单行文本item布局省得自己写item的XML。这个案例没有网络请求列表数据直接塞在内存数组里所以你看不到加载进度条接入真实接口时再考虑ProgressBar和加载状态管理。想升级成RecyclerView也简单只是要多写Adapter和LayoutManager两个类适合跑通本例后再改。5.3 三条验证路径logcat、断点、清数据重跑第一崩溃看logcat。闪退时打开底部Logcat窗口搜索过滤Exception关键词红色堆栈会直接指到是哪个Activity没注册对照第3章的manifest检查。第二断点验证数据。在FriendsActivity的onCreate里给username赋值那一行打断点以Debug方式运行登录后看Variables窗口里username的值是不是登录页输入的账号。这一步能把“数据到底传没传过来”钉死。第三清数据重跑链路。系统设置→应用→找到应用→清除数据回到首次安装状态再按“注册→回填→登录→进列表”走一遍最后按返回键确认是直接退出还是退到登录页登录页已finish的话应该直接退应用。最后补一个每次改完必查的习惯注册成功返回后账号是否自动回填直接点登录不注册是否被“账号或密码错误”挡住。这两条是这条链路最容易回归出问题的边界比主路径更能暴露跳转逻辑的疏漏。本文还有配套的精品资源点击获取