28、Android基础:Activity生命周期、Intent与Bundle、布局文件(XML)基础
说实话,Android开发入门,绕不开的就是Activity。它就像你App里的一个页面,一个窗口。你打开微信,看到聊天列表,那是一个Activity;点进某个人的对话框,那是另一个Activity。今天我们就来聊聊Activity的“生老病死”,以及怎么在页面之间传递消息、怎么把界面画出来。
一、Activity生命周期——它到底经历了什么?
Activity从创建到销毁,会经历一系列回调。我刚开始学的时候,总觉得这些回调很抽象,直到有一次调试一个闪退问题,才真正体会到生命周期的重要性。
核心回调有7个,按顺序来:
- onCreate():Activity第一次创建时调用。做初始化工作,比如加载布局、绑定事件。
- onStart():Activity变得可见,但还不能交互。
- onResume():Activity准备好和用户交互了。这是你App真正“活”起来的时刻。
- onPause():另一个Activity要覆盖上来,当前Activity暂停。保存一些轻量级数据,比如用户输入的内容。
- onStop():Activity完全不可见。释放资源,比如停止动画、解绑广播。
- onRestart():Activity从停止状态重新启动。很少单独用,但要知道有这回事。
- onDestroy():Activity被销毁。清理所有资源,防止内存泄漏。
重要提醒:onPause()里不要做耗时操作,比如网络请求、数据库写入。因为onPause执行完,下一个Activity才能显示。你想想看,用户点击了一个按钮,结果卡了半秒才跳转,体验多差。
我曾经在一个项目里,把大量数据保存逻辑写在了onPause里,结果导致页面切换卡顿。后来改到onStop里,问题就解决了。嗯,这里要注意,onStop也不适合做太重的操作,但比onPause宽松一些。
二、Intent与Bundle——页面之间的“信使”
Activity之间怎么通信?靠Intent。它就像一个信封,里面装着你要去的目的地(目标Activity),还可以附带一些数据(Bundle)。
2.1 显式Intent
直接指定要启动哪个Activity。最常用。
// 从MainActivity跳转到DetailActivity
val intent = Intent(this, DetailActivity::class.java)
startActivity(intent)
2.2 隐式Intent
不指定具体类,而是指定动作(Action)和数据(Data)。系统会找到能处理这个Intent的Activity。
// 打开浏览器
val intent = Intent(Intent.ACTION_VIEW, Uri.parse("https://www.example.com"))
startActivity(intent)
我个人习惯,能用显式Intent就用显式,因为更安全、更可控。隐式Intent容易引发冲突,比如用户装了多个浏览器,系统会弹窗让用户选择。
2.3 Bundle——给Intent“塞点料”
Bundle就是一个键值对容器。你可以把字符串、整数、对象等放进去,然后通过Intent传递。
// 发送方
val intent = Intent(this, DetailActivity::class.java)
val bundle = Bundle().apply {
putString("name", "张三")
putInt("age", 25)
}
intent.putExtras(bundle)
startActivity(intent)
// 接收方(在DetailActivity中)
val name = intent.getStringExtra("name")
val age = intent.getIntExtra("age", 0)
小技巧:如果传递的数据比较复杂,比如一个用户对象,建议用Serializable或Parcelable。我个人更推荐Parcelable,性能更好。Kotlin里可以用@Parcelize注解,写起来很爽。
三、布局文件(XML)基础——把界面画出来
Android的界面,说白了就是用XML文件描述的。你写一个XML,系统把它解析成View树,然后渲染到屏幕上。
3.1 常用布局容器
| 布局名称 | 特点 | 适用场景 |
|---|---|---|
| LinearLayout | 线性排列,水平或垂直 | 简单的列表、表单 |
| RelativeLayout | 相对定位,子View之间可以相互参照 | 复杂布局,但嵌套层级容易变深 |
| ConstraintLayout | 约束布局,扁平化,性能好 | 几乎任何场景,强烈推荐 |
| FrameLayout | 帧布局,子View层叠 | Fragment容器、覆盖层 |
我现在的项目,基本只用ConstraintLayout。为什么?因为它能减少布局嵌套,提升渲染性能。你想想看,一个页面如果嵌套了五六层LinearLayout,渲染起来得多慢。
3.2 一个简单的布局示例
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/titleText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
<Button
android:id="@+id/clickBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="点击"
app:layout_constraintTop_toBottomOf="@id/titleText"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:layout_marginTop="16dp" />
</androidx.constraintlayout.widget.ConstraintLayout>
这段代码很简单:一个TextView显示文字,一个Button在它下面。注意看约束条件,我用layout_constraintTop_toTopOf="parent"把TextView固定在顶部居中,然后用layout_constraintTop_toBottomOf把Button放在TextView下方。
避坑指南:我曾经在ConstraintLayout里忘了给某个View加约束,结果运行时它直接跑到了屏幕左上角(0,0)位置。调试了半天才发现。记住:ConstraintLayout里的每个View,至少要有水平和垂直两个方向的约束,否则它不会乖乖待在你想要的位置。
四、知识体系总览
下面这张图,把今天讲的核心内容串起来了。你可以把它当作一个思维导图来理解。
五、实战要点总结
- 生命周期要牢记:onCreate做初始化,onPause保存轻量数据,onDestroy释放资源。别搞反了。
- Intent传数据:小数据用Bundle,大数据用Parcelable。别把Bitmap直接塞Intent里,会爆的。
- 布局选型:能用ConstraintLayout就别用多层嵌套。扁平化布局,性能更好。
- 调试技巧:如果布局显示不对,先检查约束条件是否完整。我经常用Layout Inspector看View树,很直观。
好了,今天的内容就到这里。Activity生命周期、Intent与Bundle、布局文件,这三块是Android开发的基石。你把这些搞懂了,后面学Fragment、Jetpack Compose都会轻松很多。
公众号:蓝海资料掘金营,微信deep3321