Android学习路线(十五)Activity生命周期——重新创建(Recreating)一个Activity

有几个你的activity由于正常行为被销毁的场景,例如当用户点击了返回键,或者你的activity接收到自身调用 finish()方法发送的销毁信号。系统还可能会销毁那些被停止后长时间没有被使用到的activity,或者前台的activity需要更多的资源,系统会关闭后台进程来回收内存。

当你的activity由于用户点击返回键或者自己关闭而被销毁,这个Activity 实例在系统的概念上已经永远消失,因为这个行为表示这个activity不再被需要。然而,如果是由于系统限制(而不是普通的应用行为)导致系统销毁activity实例,那么即使Activity 实例已经消失,系统会记得它曾经存在过,所以当用户再次回到它时,系统会使用当时销毁activity时保存的数据集来为它重新创建一个实例。这个被系统使用来载入activity之前状态的数据集被称为"instance state" ,它是一个键值对的集合,被存储在一个Bundle 对象中。

注意: 每次用户切换横竖屏时你的activity都会被销毁然后重新创建。当屏幕方向改变时,系统销毁并重建前台activity是由于屏幕配置已经变化,你的activity可能需要加载另一个资源(例如布局)。

在默认情况下,系统使用Bundle instance state 来存放每个View对象的信息。因此,如果你的应用被销毁并重建,布局会被重新加载到之前的状态,不需要其他代码。然而,你的activity可能有更多的状态希望被重新载入,例如记录用户在activity中进程的成员变量。

提示: 为了让Android系统恢复你的activity中的view的状态,每个view都必须拥有一个唯一的ID,通过android:id 属性被指定。

为了保存关于activity状态的附加的数据,你必须覆盖onSaveInstanceState() 方法。当用户离开你的activity时系统会调用这个方法,通过它,当你的activity被异常销毁时Bundle 对象会被保存起来。如果系统之后必须重新创建activity实例,它会将相同的Bundle 对象同时传给onRestoreInstanceState() 和onCreate() 方法。

图 2. 当系统开始停止你的activity时,它会调用onSaveInstanceState() (1)方法,因此你可以指定你想要的数据保存起来。如果这个activity被销毁,那么当同样的实例被创建的时候,系统会将同样的状态数据同时传给onCreate() 方法 (2) 和onRestoreInstanceState() 方法(3)。

保存Activity状态


当你的activity开始停止时,系统调用onSaveInstanceState() ,这样你的activity可以使用键值对来保存状态信息。这个方法的默认实现会保存activity的view的层次结构,例如EditText中的文本或者ListView的滑动位置。

要为你的activity保存额外的状态信息,你必须实现onSaveInstanceState() 方法,并且把信息添加到Bundle 对象中。例如:

static final String STATE_SCORE = "playerScore";
static final String STATE_LEVEL = "playerLevel";
...

@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
    // Save the user's current game state
    savedInstanceState.putInt(STATE_SCORE, mCurrentScore);
    savedInstanceState.putInt(STATE_LEVEL, mCurrentLevel);
    
    // Always call the superclass so it can save the view hierarchy state
    super.onSaveInstanceState(savedInstanceState);
}

注意: 一定要调用onSaveInstanceState() 方法的父类的实现,这样默认的实现会保存view层次结构的状态。

恢复Activity的状态


当你的activity在销毁后被重建,你可以通过系统传递给你的Bundle 对象来恢复你所保存的状态。onCreate() 和onRestoreInstanceState() 会同时受到相同的包含状态信息的Bundle 对象。

由于onCreate() 方法在系统创建一个新的activity实例和重建activity实例时都会被调用,在你尝试使用状态Bundle时,你必须要检查它是否为空,这样系统就会创建一个新的activity实例,而不是重建之前被销毁的那个。

例如,下面是如何在onCreate()方法中恢复状态:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState); // Always call the superclass first
   
    // Check whether we're recreating a previously destroyed instance
    if (savedInstanceState != null) {
        // Restore value of members from saved state
        mCurrentScore = savedInstanceState.getInt(STATE_SCORE);
        mCurrentLevel = savedInstanceState.getInt(STATE_LEVEL);
    } else {
        // Probably initialize members with default values for a new instance
    }
    ...
}

与其在在onCreate() 方法中恢复状态,你可以选择实现onRestoreInstanceState()方法,系统会在onStart() 方法后调用。系统只会在有保存的数据需要被恢复时才会调用onRestoreInstanceState() 方法,因此你没有必要检查Bundle 是否为空:

public void onRestoreInstanceState(Bundle savedInstanceState) {
    // Always call the superclass so it can restore the view hierarchy
    super.onRestoreInstanceState(savedInstanceState);
   
    // Restore state members from saved instance
    mCurrentScore = savedInstanceState.getInt(STATE_SCORE);
    mCurrentLevel = savedInstanceState.getInt(STATE_LEVEL);
}

注意: 一定要调用onSaveInstanceState() 方法的父类的实现,这样默认的实现会保存view层次结构的状态。

学习更多关于在运行时重建你的activity(例如屏幕旋转)的信息,请参阅Handling Runtime Changes

### 解决方案分析 当使用 Anaconda 创建虚拟环境时,如果发现缺少 `bin` 或 `Scripts` 文件夹,通常是因为在创建环境中未指定 Python 版本或其他必要参数。以下是对此问题的深入解析和解决方案。 #### 1. **原因分析** - 如果在创建虚拟环境时未显式指定 Python 版本,则可能会导致某些核心组件缺失[^3]。 - 虚拟环境中可能仅包含基础元数据文件夹(如 `conda-meta`),而缺乏实际执行所需的二进制文件或脚本文件夹(如 `bin` 或 `Scripts`)[^3]。 - 这种情况可能导致无法正确激活或使用该虚拟环境,因为必要的可执行文件不存在。 #### 2. **解决方法** ##### 方法一:重新创建虚拟环境并指定 Python 版本 通过明确指定 Python 版本来确保所有必需组件被正确安装: ```bash conda create -n myenv python=3.8 ``` 这一步会自动下载对应版本的 Python 及其依赖项,并生成完整的结构,包括 `bin` 和其他子目录。 ##### 方法二:手动修复现有环境 对于已存在的但存在问题的虚拟环境,可以尝试以下步骤: 1. 激活目标环境: ```bash conda activate myenv ``` 2. 显式安装 Python 到当前环境中: ```bash conda install python=3.8 ``` 此命令将补充缺失的关键组件,从而恢复正常的文件夹结构[^3]。 3. 验证修复效果: 检查是否存在 `bin` 或 `Scripts` 文件夹及其内容: ```bash ls $(conda info --base)/envs/myenv/bin ``` ##### 方法三:复制 base 环境中的关键文件 作为临时补救措施,可以从 `base` 环境中复制必要的脚本到有问题的虚拟环境中。例如: ```bash cp -r $(conda info --base)/bin/* $(conda info --base)/envs/myenv/bin/ ``` 注意:这种方法适用于紧急情况下快速解决问题,但并非推荐的最佳实践。 #### 3. **验证与测试** 完成上述任一方法后,请确认新创建或修复后的虚拟环境能够正常工作: ```bash conda activate myenv which python python --version ``` 以上命令应返回正确的路径及 Python 版本号,表明环境已被成功设置。 --- ### 示例代码片段 以下是一个简单的 Bash 脚本,用于自动化检测和修正虚拟环境的问题: ```bash #!/bin/bash ENV_NAME="myenv" PYTHON_VERSION="3.8" # 检测 bin 文件夹是否存在 if [ ! -d "$(conda info --base)/envs/$ENV_NAME/bin" ]; then echo "Bin folder missing, recreating environment..." conda remove -n $ENV_NAME --all conda create -n $ENV_NAME python=$PYTHON_VERSION else echo "Environment is intact." fi # 激活并验证 conda activate $ENV_NAME echo "Active environment: $(basename $(pwd))" python --version ``` --- ### 总结 Anaconda 创建虚拟环境时缺少 `bin` 或 `Scripts` 文件夹通常是由于未指定 Python 版本引起的。通过重新创建环境、显式安装 Python 或手动修补已有环境等方式均可有效解决问题[^3]。 ---
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值