防止Activity被重新创建

本文介绍如何通过配置AndroidManifest.xml文件中的Activity标签,避免因屏幕旋转等原因导致Activity重建的方法。通过设置android:configChanges属性,可以指定Activity在特定系统配置改变时不进行重建。

Activity在系统配置发生改变之后会重新创建,我们常见的是在手机旋转屏幕时activity就被重新创建了。那么怎么样才能不被创建呢?我们先来看一下系统的那些内容被改变后Activity会被重新创建。
系统的配置在Configuration类中,我们来查看Configuration类中的成员,看看他们分别代表的意思。

  1. mcc: SIM卡唯一标示IMSI(国际移动用户识别码)中的国家代码,由三位数字组成,中国为460。此项标示mcc代码发生了改变
  2. mnc: SIM卡的唯一标示IMSI(国际移动用户识别码)中的运营商代码,由2位数字组成,中国移动TD系统为00,中国联通为01,此项标示mnc发生改变
  3. locale:设备的本地位置发生了改变,一般指切换了系统语言。
  4. touchscreen:触屏发生了改变
  5. keyboard:键盘类型发生了改变,比如使用了外接键盘
  6. keyboardHidden:键盘的可访问性发生了改变,比如用户调出了键盘
  7. navigation:系统导航发生了改变,比如采用了轨迹导航,这个有点费解,很难发生,可以忽略它。
  8. srceenLayout:屏幕布局发生了改变,很可能是激活了另外一个显示设备
  9. frontScale:系统字体缩放比例发生了变化,比如用户选择了一个新字号
  10. uiMode:用户界面模式发生了改变,比如是否开启了夜间模式(API8新加)
  11. orientation:屏幕方向发生了改变,这个是最常用的,比如旋转了手机屏幕
  12. sreenSize:当屏幕尺寸信息发生改变,当选装设备时,屏幕尺寸会发生改变,这个选项比较特殊,它和编译选项有关,当编译选项中的minSdkVersion 和 targetSdkVersion均低于13时,此选项不会到时Activity重启,负责Activity将重启(api13)添加
  13. smallScreenSize:设备的物理尺寸发生改变,这个项目和屏幕的方向没关系,仅仅表示在实习的物理屏幕的尺寸发生改变的时候,比如用户切换到了外部的显示设备,这个选项和srceenSize一样,当编译选项中中的minSdkVersion和targetSdkVersion均低于13时,此选项不会导致Activity重启,负责将导致Activity重启(API13新添加)
  14. layoutDirection:当布局发生变化,这个属性用的比较少,正常情况下无须修改布局的layoutDirection属性(API17新添加)

    上面列出的项目很多,其实我们常用的就 locale、orientation 和 keyboardHidden这三项。

那么我们来看一下怎么让这些配置改变之后,Activity不重建呢?其实很简单。
比如我们不想让 屏幕方向发生改变时Activity重建,那么只需在AndroidManfest.xml中对应的Activity标签中添加一句 android:configChanges=”orientation”

    <activity android:name=".MainActivity"
            android:configChanges="orientation"  //添加这句
            >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

那么当屏幕发生改变时,Activity不会被重建。但会回调Activity中的onConfigurationChanged方法。我在实际应用中发现:只添android:configChanges=”orientation” 不能阻止Activity重建,原因在于:在屏幕旋转是srceenSize 也发生了改变。所有最后决定这样写:android:configChanges=”orientation|screenSize”
那么我们来看一下我的代码,以及运行结果
MainActivity.java

package com.simple.myapplication;

import android.content.Intent;
import android.content.res.Configuration;
import android.os.PersistableBundle;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;

public class MainActivity extends AppCompatActivity {

    private static final String TAG = "MainActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        findViewById(R.id.btn).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                startActivity(new Intent(MainActivity.this,SecondActivity.class));

            }
        });

        Log.i(TAG, "onCreate: ");
    }

    @Override
    public void onCreate(Bundle savedInstanceState, PersistableBundle persistentState) {
        super.onCreate(savedInstanceState, persistentState);

    }

    @Override
    protected void onStart() {
        super.onStart();
        Log.i(TAG, "onStart: ");
    }

    @Override
    protected void onRestart() {
        super.onRestart();
        Log.i(TAG, "onRestart: ");
    }

    @Override
    protected void onResume() {
        super.onResume();
        Log.i(TAG, "onResume: ");
    }

    @Override
    protected void onStop() {
        super.onStop();
        Log.i(TAG, "onStop: ");
    }

    @Override
    protected void onPause() {
        super.onPause();
        Log.i(TAG, "onPause: ");
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.i(TAG, "onDestroy: ");
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        outState.putInt("key",1);
        super.onSaveInstanceState(outState);
        Log.i(TAG, "onSaveInstanceState: ");
    }

    @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        int i  = savedInstanceState.getInt("key");
        super.onRestoreInstanceState(savedInstanceState);
        Log.i(TAG, "onRestoreInstanceState:");
    }


     /**
     * AndroidManifest如果添加 configChanges ="..." 使得Acivity不重建
     * 则会调用这个方法
     * @param newConfig
     */
    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        Log.i(TAG, "onConfigurationChanged: "+newConfig.orientation);
    }
}



AndroidManifest.xml

 <activity android:name=".MainActivity"
            android:configChanges="orientation|screenSize"
            >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
运行结果:
com.simple.myapplication I/MainActivity: onConfigurationChanged: 2
com.simple.myapplication I/MainActivity: onConfigurationChanged: 1
com.simple.myapplication I/MainActivity: onConfigurationChanged: 2

注意我这里的指定的minSdkVersion和tagetSdkVersion大于13,所以为了防止屏幕旋转时Activity重启,除了orientation,我们还要添加srceenSize。

<think>我们正在讨论AndroidActivity创建过程和生命周期。根据用户的问题,他想要了解Android Activity创建过程(creation process)和生命周期(lifecycle)。结合之前的对话历史,用户之前询问过一段WindowManager的日志,但当前问题转向了Activity创建和生命周期,因此我们需要专注于这个新问题。 参考引用: [^1] 提到了ActivityTaskManagerService.Lifecycle的构造,这涉及到系统服务中Activity生命周期的管理。 [^2] 解释了Android Activity Lifecycle的基本概念,包括进程创建、onCreate()的调用以及主线程的初始化。 [^3] 和 [^4] 似乎与当前问题关联不大,但[^3]提到了启动应用时进程的问题,[^4]是关于Hilt依赖注入框架的结论。 注意:用户要求尽可能参考上一次的问题和回答,但上一次的问题是关于WindowManager的日志,而这次是全新的关于Activity创建和生命周期的问题,因此我们重新组织答案。 我们将按照以下结构回答: 1. Activity创建过程(从启动到onCreate) 2. Activity生命周期的完整过程(各个回调方法) 3. 结合系统服务(如ActivityTaskManagerService)解释管理机制 4. 进程和主线程的关系(引用[^2]的内容) 同时,我们需要遵循系统指令: - 行内数学表达式用$...$(但本问题可能较少使用,如果有时间相关的计算可以使用) - 独立公式用$$...$$ - 使用中文 - 生成相关问题 - 引用的地方在末尾添加引用标识 由于这是一个技术解释,我们将使用清晰的步骤和代码示例(如生命周期方法的重写)来说明。 注意:我们引用[^2]的内容来解释进程创建和onCreate()的关系。 开始回答:</think>### Android Activity 创建过程与生命周期详解 #### 一、Activity 创建核心流程 当系统启动 Activity 时,会经历以下关键步骤: 1. **进程创建 (Process Creation)** - 当应用组件启动且无其他组件运行时 - Android 系统创建新的 Linux 进程 - 进程初始化后调用 `Application.onCreate()` - 创建主线程 (UI 线程) [^2] $$ \text{进程创建} \rightarrow \text{主线程初始化} \rightarrow \text{Activity 实例化} $$ 2. **Activity 实例化** - `ActivityThread.handleLaunchActivity()` 触发 - 通过反射调用 Activity 构造器 - 创建 PhoneWindow 对象(关联 DecorView) - 加载主题资源 3. **生命周期回调** ```java // 典型调用序列 onCreate() → onStart() → onResume() ``` - `onCreate()`:初始化 UI (setContentView) 和数据 - `onStart()`:Activity 可见但未交互 - `onResume()`:进入前台可交互状态[^2] #### 二、完整生命周期状态机 ```mermaid stateDiagram-v2 [*] --> Created: 启动Activity Created --> Started: onStart() Started --> Resumed: onResume() Resumed --> Paused: 部分遮挡/失去焦点 Paused --> Resumed: 返回前台 Paused --> Stopped: 完全遮挡 Stopped --> Resumed: 重启并返回前台 Stopped --> Destroyed: onDestroy() Destroyed --> [*] ``` 关键回调方法: | 方法 | 触发场景 | 必须操作 | |------|----------|----------| | `onCreate()` | 首次创建 | 初始化布局和数据绑定 | | `onRestart()` | 从停止状态恢复 | 刷新过期数据 | | `onPause()` | 失去焦点 | 保存临时数据 | | `onStop()` | 完全不可见 | 释放占用资源 | | `onDestroy()` | 销毁前 | 清理内存防止泄漏 | #### 三、系统服务协同机制 1. **ActivityTaskManagerService (ATMS)** - 管理 Activity 栈和任务 (Task) - 通过 `Lifecycle` 类控制生命周期[^1] ```java // 系统内部调用链 ATMS.startActivity() → ActivityThread.scheduleLaunchActivity() ``` 2. **WindowManager 交互** - 创建窗口关联 Surface - 处理旋转时调用 `applyFixedRotationTransform()` - 完成时触发 `finishFixedRotationTransform()` 日志 - 错误处理可能导致闪屏(见前文分析) #### 四、进程与线程模型 1. **单线程原则** - UI 操作必须在主线程执行 - 耗时操作需移至工作线程 $$ \text{主线程响应时间} \leq 16ms \text{ (60fps)} $$ 2. **进程回收机制** - 当系统内存不足时 - 优先销毁 `onStop()` 状态的 Activity - 重建时调用 `onCreate()` 并恢复保存状态 #### 五、最佳实践 1. **生命周期敏感组件** ```kotlin class MyActivity : AppCompatActivity() { private lateinit var sensorManager: SensorManager override fun onCreate() { sensorManager = getSystemService(SENSOR_SERVICE) as SensorManager sensorManager.registerListener(...) } override fun onPause() { sensorManager.unregisterListener() // 避免资源泄漏 super.onPause() } } ``` 2. **状态保存与恢复** ```java override fun onSaveInstanceState(outState: Bundle) { outState.putString("KEY", criticalData) } override fun onCreate(savedInstanceState: Bundle?) { if (savedInstanceState != null) { criticalData = savedInstanceState.getString("KEY") } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值