news 2026/9/16 14:11:36

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

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
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,而是直接再建三个Activity:LoginActivity、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,嵌套层级少,初学者看着不晕。密码输入框一定要设inputType="textPassword",否则键盘上方会明文显示输入内容。

<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:padding="24dp"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="注册新账号" android:textSize="24sp" android:textStyle="bold" /> <!-- 账号输入框,maxLines=1 防止实体键盘换行 --> <EditText android:id="@+id/et_register_account" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="请输入账号" android:inputType="text" android:maxLines="1" /> <!-- 密码框,输入内容会被圆点遮盖 --> <EditText android:id="@+id/et_register_password" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="请输入密码" android:inputType="textPassword" android:maxLines="1" /> <Button android:id="@+id/btn_register" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="注册并返回登录" /> </LinearLayout>

根布局宽高用match_parent铺满屏幕,padding="24dp"让控件不贴边。控件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_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <TextView android:id="@+id/tv_welcome" android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="16dp" android:textSize="18sp" android:text="欢迎" /> <!-- height=0dp + weight=1 占满剩余空间 --> <ListView android:id="@+id/lv_friends" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" /> </LinearLayout>

ListView的layout_height用0dp配合layout_weight="1",是LinearLayout里占满剩余空间的常用写法,比写死数值更适应不同屏幕。到这一步三张界面就绪,下一步解决三个页面怎么被正确注册、怎么跳。

3. AndroidManifest注册与页面跳转:显式Intent怎么把三个页面串起来

界面只是静态骨架,真正让注册、登录、好友列表三页动起来的是Intent。这一章把manifest注册和三种跳转写法一次说清。

3.1 先改AndroidManifest.xml:launcher是谁、exported怎么设

模板建出来的MainActivity默认是启动页。做这个案例时我一般删掉MainActivity和activity_main.xml,把LoginActivity设为入口。打开AndroidManifest.xml,确认三个Activity都有对应的节点,并在LoginActivity上配MAIN和LAUNCHER的intent-filter。

<application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:theme="@style/Theme.AppCompat.Light.NoActionBar"> <activity android:name=".FriendsActivity" /> <activity android:name=".RegisterActivity" /> <!-- 登录页作为启动入口 --> <activity android:name=".LoginActivity" android:exported="true"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application>

从Android 12(API 31)开始,声明了intent-filter的Activity必须写android:exported,true表示允许其他应用唤起,launcher入口固定写true;RegisterActivity和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 成员变量 ActivityResultLauncher<Intent> 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塞进去的那个Intent,getStringExtra的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_info",key统一为account/password
没注册直接登录闪退getString默认值没写,返回null后调equals默认值写"",判空提前
点登录按钮完全没反应按钮没setOnClickListener,或回调里return了但没Toast先检查监听器是否绑定,判空分支必须有提示

第三个坑再补充一句:如果按钮绑了监听器仍无反应,优先看XML里Button是不是被其他View遮住了,常见的是根布局里某个控件把按钮盖住。真机调试时打开开发者选项里的“显示布局边界”能直接看出来。

注册数据落盘、登录校验通过,链路只剩最后一段:把登录的用户名带进好友列表页,并验证全流程。

5. 把用户名带进好友列表页,并验证整条跳转链路

5.1 Intent Extra传用户名,没取到给默认值

登录成功后启动FriendsActivity,在startActivity前加一行putExtra:

Intent 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 = {"张伟", "李娜", "王强", "赵敏"}; ArrayAdapter<String> 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的话应该直接退应用)。

最后补一个每次改完必查的习惯:注册成功返回后账号是否自动回填,直接点登录不注册是否被“账号或密码错误”挡住。这两条是这条链路最容易回归出问题的边界,比主路径更能暴露跳转逻辑的疏漏。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/16 14:10:04

MATLAB纯函数实现OFDMA全链路仿真与调试

简介&#xff1a;本资源是一份面向通信工程专业学生与无线通信初学者的OFDMA系统MATLAB仿真实践包&#xff0c;聚焦4G/5G多载波多址接入原理的理解与建模验证。压缩包共4个文件&#xff08;3个核心MATLAB脚本.m 1个中文说明txt&#xff09;&#xff0c;总大小仅3KB&#xff0c…

作者头像 李华
网站建设 2026/9/16 14:09:06

Kubernetes单元测试利器:fake-client原理与实践指南

1. 理解fake-client在Kubernetes测试中的定位fake-client是client-go库中专门为单元测试设计的模拟客户端实现。它完美复刻了真实Kubernetes客户端的行为模式&#xff0c;但所有操作都在内存中完成&#xff0c;不需要真实的Kubernetes集群支持。这种设计使得开发者可以&#xf…

作者头像 李华
网站建设 2026/9/16 14:09:03

librealsense macOS 源码构建与打包指南:从工具链安装到应用分发

librealsense macOS 源码构建与打包指南&#xff1a;从工具链安装到应用分发 【免费下载链接】librealsense RealSense SDK 项目地址: https://gitcode.com/GitHub_Trending/li/librealsense 本篇指南以仓库 doc/installation_osx.md 为主线&#xff0c;完整讲解 RealSe…

作者头像 李华
网站建设 2026/9/16 14:08:13

Python文件操作与IO流详解:从基础到高级技巧

1. Python文件操作基础与IO流概念1.1 理解IO的本质在编程中&#xff0c;IO&#xff08;Input/Output&#xff09;是程序与外部世界交互的桥梁。想象你正在用手机拍照&#xff1a;按下快门是输入&#xff08;Input&#xff09;&#xff0c;保存照片到相册是输出&#xff08;Outp…

作者头像 李华
网站建设 2026/9/16 14:06:42

NLTK与PyTorch结合:文本分类预处理到模型设计完整源码

简介&#xff1a;一份基于深度学习的自动文本分类系统设计源码&#xff0c;采用Python与NLTK工具库开发&#xff0c;面向需要处理文本归类、情感分析、垃圾邮件识别等场景的开发者与研究者&#xff0c;适合快速构建和扩展分类模型。资源包共37个文件&#xff0c;其中16个Python…

作者头像 李华