Android App 生命周期解析:为什么你的 AI 生成的 App 在旋转时仍能存活
Source: Dev.to
活动生命周期:五个状态
onCreate() → onStart() → onResume() → [Activity visible and interactive]
↓
onPause() → onStop() → onDestroy()
1. onCreate()
- 当 Activity 首次创建时调用。
- 初始化 UI,设置数据绑定。
- 恢复已保存的状态(后面会详细说明)。
2. onStart()
- Activity 对用户可见。
- 启动摄像头、位置服务等资源。
- 此时尚未可交互。
3. onResume()
- Activity 现在已完全可交互。
- 用户可以点击按钮、输入文字等。
- 启动动画或恢复视频播放。
4. onPause()
- 用户正在离开该 Activity(另一个应用进入前台)。
- 在此保存关键数据。
- 停止动画,暂停视频。
- 注意: 你只有约 500 ms 的时间,系统可能会在此后杀死你的应用。
5. onStop()
- Activity 不再可见。
- 清理占用较大的资源(例如数据库连接)。
- 系统可能会在此处杀死你的应用以释放内存。
6. onDestroy()
- Activity 正在被销毁(用户按了返回键或系统正在杀死它)。
- 最终清理。
问题:配置更改(旋转)
当用户旋转手机时,Android 会销毁当前的 Activity 并从头重新创建它。
User rotates phone
↓
onPause() → onStop() → onDestroy() [old Activity destroyed]
↓
onCreate() → onStart() → onResume() [new Activity created]
后果
- 所有局部变量都会丢失。
- 任何内存中的数据都会消失。
- UI 状态被重置。
- 用户会看到 UI 重建时的闪烁/闪光。
这就是许多 AI 生成的应用在旋转时崩溃的原因——开发者没有正确保存状态。
方案 1:使用 ViewModel 在配置更改时保持存活
ViewModel 是一个 Jetpack 组件,能够在配置更改时保持存活。存放在 ViewModel 中的数据 不会 在 Activity 旋转时被销毁。
Kotlin 代码示例
// 1. Define your ViewModel
class UserViewModel : ViewModel() {
private val _userName = MutableLiveData("")
val userName: LiveData<String> = _userName
fun setUserName(name: String) {
_userName.value = name
}
}
// 2. In your Activity, use the ViewModel
class MainActivity : AppCompatActivity() {
private val viewModel: UserViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val nameInput = findViewById<EditText>(R.id.nameInput)
// When user types, save to ViewModel
nameInput.addTextChangedListener { text ->
viewModel.setUserName(text.toString())
}
// Observe ViewModel data
viewModel.userName.observe(this) { name ->
nameInput.setText(name)
}
}
}
为什么这样可行
- ViewModel 的作用域是 Activity。
- Android 在配置更改期间会保持它的实例。
- 数据在旋转时仍然持久化。
- UI 通过 LiveData 自动更新。
方案 2:使用 Jetpack Compose 与 rememberSaveable
如果您使用 Compose(现代 Android UI 框架),该模式甚至更简单。
@Composable
fun UserScreen() {
// This state survives rotation because of rememberSaveable
var userName by rememberSaveable { mutableStateOf("") }
Column {
TextField(
value = userName,
onValueChange = { userName = it },
label = { Text("Enter your name") }
)
Text("Hello, $userName!")
}
}
关键差异
| Compose 函数 | 旋转时是否保留 |
|---|---|
remember { } | 否 – 状态在销毁时丢失 |
rememberSaveable { } | 是 – 保存到 Bundle 并恢复 |
Compose 会在 Activity 重新创建时自动恢复已保存的状态。
Compose 重组工作原理
当发生旋转时:
- Activity 被销毁 →
rememberSaveable将其状态保存到Bundle。 - Activity 被重新创建 →
rememberSaveable从Bundle中恢复状态。 - Compose 重新组合 UI 树,使用恢复后的值渲染
TextField。
User rotates phone
↓
rememberSaveable saves state → Activity destroyed
↓
Activity recreated → rememberSaveable restores state
↓
Compose recomposes → TextField shows saved text
解决方案 3:保存到 savedInstanceState(onSaveInstanceState)
对于更复杂的数据,请使用 onSaveInstanceState() 回调。
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val nameInput = findViewById<EditText>(R.id.nameInput)
// Restore from saved state
if (savedInstanceState != null) {
val savedName = savedInstanceState.getString("userName", "")
nameInput.setText(savedName)
}
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
val nameInput = findViewById<EditText>(R.id.nameInput)
outState.putString("userName", nameInput.text.toString())
}
}
onSaveInstanceState 在 Activity 被销毁之前调用,允许您将原始类型、Parcelable 或 Serializable 放入 Bundle 中。当 Activity 重新创建时,已保存的值可在 onCreate(或 onRestoreInstanceState)中获取。
TL;DR
- Activity 生命周期 决定了何时可以安全地分配和释放资源。
- 旋转 会触发完整的销毁/重建周期,清除内存中的状态。
- ViewModel、
rememberSaveable和onSaveInstanceState是在配置更改时保留数据的三种主要方式。
实现其中一种(或组合)策略,你的 AI 生成的 Android 应用就能优雅地应对旋转。
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
outState.putString("userName", nameInput.text.toString())
}
限制
- 仅适用于
Parcelable/Serializable对象。 Bundle大约有 1 MB 的大小限制。- 不适合大型数据集。
防止旋转:禁用配置更改 (不推荐)
<!-- Add to your Activity declaration in AndroidManifest.xml -->
<activity
android:name=".MainActivity"
android:configChanges="orientation|screenSize|keyboardHidden"
android:screenOrientation="portrait" />
为什么 不 要这么做
- 用户不喜欢不能旋转的应用。
- 你会破坏依赖旋转的用户的可访问性。
- 忽视旋转的 AI 生成应用会收到差评。
Source: …
当你的应用被杀死:进程死亡
Android 可以在后台杀死整个进程以释放内存。这 不同于 配置更改。
流程
用户将你的应用切到后台
↓
系统需要内存
↓
系统杀死你的进程(调用 onDestroy())
↓
用户返回你的应用
↓
系统重新创建整个应用栈
onSaveInstanceState() 在这里仍然可用,但只能保存 UI 状态。
对于重要数据,请使用持久化存储:
- Room(本地数据库)
- SharedPreferences
- DataStore(Jetpack)
Room 示例
@Database(entities = [User::class], version = 1)
abstract class AppDatabase : RoomDatabase() {
abstract fun userDao(): UserDao
}
@Dao
interface UserDao {
@Insert
suspend fun insertUser(user: User)
@Query("SELECT * FROM users LIMIT 1")
fun getUser(): Flow<User>
}
重启后恢复数据
class MainActivity : AppCompatActivity() {
private val db = AppDatabase.getInstance(this)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
lifecycleScope.launch {
db.userDao().getUser().collect { user ->
// Restore UI with user data
}
}
}
}
摘要表
| 场景 | 解决方案 | 是否在旋转后仍存活 | 数据限制 |
|---|---|---|---|
| 配置更改(旋转) | ViewModel + LiveData | 是 | 无限制 |
| 配置更改(Compose) | rememberSaveable | 是 | 约 1 MB(Bundle) |
短暂暂停(onPause) | ViewModel | 是 | 无限制 |
| 进程死亡 | Room / SharedPreferences / DataStore | 是 | 设备存储 |
| 用户按返回键 | 未保存 | 否 | 不适用 |
AI 生成的应用程序与生命周期
当您使用 Claude Code 或其他任何 AI 生成 Android 应用时,务必验证:
- ✅ 它是否在旋转时不会崩溃?
- ✅ 它是否使用
ViewModel或rememberSaveable? - ✅ 它是否将重要数据持久化到数据库中?
- ✅ 它是否正确实现了用于清理的
onPause()?
生成质量较差的应用常见问题
- 完全忽视生命周期。
- 旋转时数据丢失。
- 进程死亡时崩溃。
- 未保存用户输入。
我们的模板已正确处理所有这些问题。
图示(供参考)
┌─────────────────────────────────────────────────────┐
│ 活动生命周期流程 │
└─────────────────────────────────────────────────────┘
onCreate()
↓
onStart()
↓
onResume() ← [用户交互中]
↙ ↖
onPause() [旋转:销毁并重新创建]
↓
onStop()
↓
onDestroy()
ViewModel 在旋转后仍然存在 ✓
rememberSaveable 在旋转后仍然存在 ✓
局部变量在旋转后不保留 ✗
结论
- 使用 ViewModel 或
rememberSaveable来管理 UI 状态。 - 使用 Room、SharedPreferences 或 DataStore 来存储持久化数据。
- 在
onSaveInstanceState()中保存状态,以应对特殊情况。 - 在发布前测试旋转。
所有 8 个模板都正确处理了生命周期。