目录

  • 零、参考
  • 一、Activity定义
  • 二、任务栈(Task)
  • 三、生命周期
  • (一)Activity的四种状态
  • (二)正常情况下的回调方法
  • (三)异常情况下的回调方法
  • 四、启动模式
  • (一)Standard(标准模式)
  • (二)SingleTop(栈顶复用)
  • (三)SingleTask(栈内复用)
  • (四)SingleInstance(单例模式)
  • 五、用到的填坑方式
  • 六、注释


零、参考

一、Activity定义

Android系统提供给我们的,与用于交互的接口(界面)。

二、任务栈(Task)

  1. 任务栈是一个栈结构,具有先进先出的特性,用于存放所有的Activity组件。
  2. 栈中Activity的顺序就是按照它们被打开的顺序依次存放的。
  3. Android系统使用任务栈的方式来有序地管理其中的Activity,并决定哪个Activity与用户进行交互——只有在任务栈栈顶的Activity才可以跟用户进行交互。
  4. 触发操作和背后原理:
  • 打开一个新的Activity或者退出当前Activity,将在一个称为任务栈的结构中添加或者减少一个Activity组件。
  • 退出应用程序时,必须把所有的任务栈中所有的activity清除出栈时,任务栈才会被销毁。当然任务栈也可以移动到后台, 并且保留了每一个activity的状态. 可以有序的给用户列出它们的任务, 同时也不会丢失Activity的状态信息。
  1. APP、Activity、Task的关系
  • 一个App中可能不止一个Task。
  • 某些特殊情况下,单独一个Activity可以独享一个Task。
  • 一个Task中的Activity可以来自不同的App。
  • 同一个App的Activity可能不在一个Task中。
  1. 任务栈结构示意图:

三、生命周期

(一)Activity的四种状态

  1. Active:Activity处于栈顶。
    注意:只是失去了与用户交互的能力。内存充足的情况下不会回收数据、成员变量等资源,除非内存不足。
  2. Paued:Activity可见但不可交互(失去焦点)。
  3. Stopped:当前Activity不可见(被另一个Activity完全覆盖)。
    注意:内存充足的情况下不会回收数据、成员变量等资源,除非内存不足。大概率资源会被收回。
  4. Killed:Activity被系统回收。

(二)正常情况下的回调方法

android系统通过任务栈 android任务栈特点_android

  1. Activity启动
  • onCreate():初始化工作,布局资源,图片预加载等。
  • onStart():用户可见,但是还处在后台,无法与用户交互。
  • onResume():前台可见,可以与用户交互交互。
  1. 被其他Activity覆盖
  • onPause():Activity处于正在停止状态。
  • onStop():Activity处于完全覆盖状态,不可见,只能在后台运行。
  1. 再次回到原Activity
  • onRestart():由不可见变为可见。
  • onStart()
  • onResume()
  1. 点击“BACK”回退键,退出当前Activity。
  • onPause()
  • onStop()
  • onDestroy():表示正在被销毁,回收,资源释放

(三)异常情况下的回调方法

1.onSaveInstanceState():保存一些临时性的数据到Bundle中

  • 由系统主动销毁一个Activity时会被自动调用。
  • 如果调用,调用将发生在onPause()或onStop()方法之前(多数在onPause()前)。
  • 调用时机(系统调用)
    • 内存不足时。
    • 用户直接按“HOME”键时。
    • 长按“HOME“”键,选择运行其他的程序时。
    • 从Activity A中启动一个新的Activity B时。
    • 屏幕方向切换时,例如从竖屏切换到横屏。
  • 是否重写?
    • 如果需要保存额外的数据时, 就需要覆写此方法,但是只适合保存瞬态数据, 比如UI控件的状态,成员变量的值等,而不应该用来保存持久化数据。
  1. onRestoreInstanceState(Bundle):获得传过来的Bundle
  • Activity重新创建时调用,通过这个方法可以恢复之前界面的状态。
  • 如果调用,调用将发生在onStart() 和 onPostCreate(Bundle)之间。
  1. onRetainNonConfigurationInstance():主要用于屏幕旋转操作,主要保存一些不适合保存在Bundle中的数据,像AsyncTask和SQLiteDatabse等,当然也可以保存任何类型数据。
  • 如果调用,调用将发生在onSaveInstanceState()之前。

  • 配合使用getLastNonConfigurationInstance()获取切换屏幕的状态或其他数据。

  • 代码演示

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);

        if (savedInstanceState != null) {
            String token = savedInstanceState.getString("key");
            Log.d(TAG, "onCreate: token" + token);
        }
        Log.d(TAG, "onCreate: execute");

        Button btnDialog = findViewById(R.id.start_dialog);
        btnDialog.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(MainActivity.this, DialogActivity.class);
                startActivity(intent);
            }
        });

        Button startNormal = findViewById(R.id.start_normal);
        startNormal.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(MainActivity.this, NormalActivity.class);
                startActivity(intent);
            }
        });
    }

    @Override
    protected void onSaveInstanceState(@NonNull Bundle outState) {
        super.onSaveInstanceState(outState);
        String token = "22334455";
        outState.putString("key", token);
    }

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

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

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

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

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

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

-logcat结果

android系统通过任务栈 android任务栈特点_android_02


-说明:启动MainActivity,点击按钮1进入NormalActivity(完全覆盖),返回MainActivity,点击按钮2进入DialogActivity(部分覆盖),再按返回键退出。

四、启动模式

(一)Standard(标准模式)

android系统通过任务栈 android任务栈特点_android系统通过任务栈_03

  • 特点
    • 在不指定启动模式的前提下,系统默认使用此模式。
    • 每次启动activity,都会新建一个实例,并将它放在栈的顶部。
    • 出现完整生命周期onCreate(),onStart(),onResume(),内存消耗大。
  • 代码演示
<activity android:name=".launchmode.FirstActivity"/>
public class FirstActivity extends AppCompatActivity {

    private static final String TAG = "FirstActivity";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_first);
        //打印当前活动的实例
        Log.d(TAG, this.toString());
        Button btn = findViewById(R.id.btn_first);
        btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(FirstActivity.this, FirstActivity.class);
                startActivity(intent);
            }
        });
    }
}
  • logcat 结果
  • android系统通过任务栈 android任务栈特点_android系统通过任务栈_04


  • 说明:每次点击一次按钮就会常见出一个新的FirstActivity实例,这里new出了5个FirstActivity实例,如果要退出程序需要连续按5次。
  • 示意图(启动和返回)
  • android系统通过任务栈 android任务栈特点_ide_05


(二)SingleTop(栈顶复用)

android系统通过任务栈 android任务栈特点_ide_06

  • 情况一:当前栈中已有该Activity实例,并且该实例位于栈顶时,这个Activity不会被重新创建,而是复用栈顶的实例,并且会将Intent对象传入,回调onNewIntent()方法。
    • 注意:此Activity它的onCreate(),onStart()方法不会被调用,因为它并没有发生改变。
  • 情况二:当前栈中已有该Activity实例,但是该实例不在栈顶时,会新建一个实例。
  • 情况三:当前栈中不存在该Activity实例时,会新建一个实例。
  • 使用场景
    • IM对话框(即时通讯)
    • 新闻客户端推送
  • 代码演示
<activity
 	android:name=".launchmode.FirstActivity"
	android:launchMode="singleTop">
    <intent-filter>
    	<action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>
<activity android:name=".launchmode.SecondActivity"/>
public class FirstActivity extends AppCompatActivity {

    private static final String TAG = "launch_FirstActivity";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_first);
        //打印当前活动的实例
        Log.d(TAG, this.toString());
        Button btn = findViewById(R.id.btn_first);
        btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
                startActivity(intent);
            }
        });
    }
}
public class SecondActivity extends AppCompatActivity {

    private static final String TAG = "launch_SecondActivity";
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);
        Log.d(TAG, this.toString());
        Button btn = findViewById(R.id.button1);
        btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(SecondActivity.this, FirstActivity.class);
                startActivity(intent);
            }
        });
    }
}
  • logcat结果
  • android系统通过任务栈 android任务栈特点_任务栈_07


  • 说明:点击FirstActivity的按钮启动SecondActivity,再点击SecondActivity的按钮重新进入到FirstActivity,但是系统创建了两个不同的FirstActivity实例,符合情况二。
  • 示意图(启动和返回)
  • android系统通过任务栈 android任务栈特点_ide_08


(三)SingleTask(栈内复用)

android系统通过任务栈 android任务栈特点_android系统通过任务栈_09

  • 特点:在同一个任务栈中只存在一个实例。
  • 流程
    • 首先会根据taskAffinity1去寻找当前是否存在一个对应名字的任务栈。
    • 如果任务栈不存在,则会创建一个新的Task。
    • 如果任务栈存在,则得到该任务栈,查找该任务栈中是否存在该Activity实例,如果存在,那么这个Activity不会被重新创建,而是移除(Destory)任务栈中在该实例之上的所有Activity,把目标实例置于栈顶并直接调用它的onNewIntent()方法。
  • 使用场景
    • 应用的主界面
  • 代码演示
<activity
 	android:name=".launchmode.FirstActivity"
	android:launchMode="singleTask">
    <intent-filter>
    	<action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>
<activity android:name=".launchmode.SecondActivity"/>
public class FirstActivity extends AppCompatActivity {

    private static final String TAG = "launch_FirstActivity";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_first);
        //打印当前活动的实例
        Log.d(TAG, this.toString());
        Button btn = findViewById(R.id.btn_first);
        btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
                startActivity(intent);
            }
        });
    }

    @Override
    protected void onRestart() {
        super.onRestart();
        Log.d(TAG, "onRestart");
    }
}
public class SecondActivity extends AppCompatActivity {

    private static final String TAG = "launch_SecondActivity";
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);
        Log.d(TAG, this.toString());
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.d(TAG, "onDestroy");
    }
}
  • logcat结果
  • android系统通过任务栈 android任务栈特点_android_10


  • 说明:在FirstActivity界面点击按钮进入到SecondActivity,然后点击后退按钮,又会重新进入FirstActivity,可以发现,再回到FirstActivity时,返回栈已经存在一个FirstActivity的实例,所以FirstActivity重新成为了栈顶Activity,并将SecondActivity的实例移除。
  • 示意图(启动和返回)
  • android系统通过任务栈 android任务栈特点_android系统通过任务栈_11


(四)SingleInstance(单例模式)

android系统通过任务栈 android任务栈特点_android_12


android系统通过任务栈 android任务栈特点_任务栈_13

  • 特点
    • 以这种模式启动的activity具有全局唯一性,即整个系统中就这么一个实例。
    • 如果在启动这样的Activity时,已经存在了一个实例,那么就会把所在的任务调度到前台,直接重用这个实例。
    • 以这种模式启动的Activity具有独占性,这个实例独享一个任务栈。
  • 使用场景
    • 呼叫来电
  • 代码演示
<activity
	android:name=".launchmode.FirstActivity">
    <intent-filter>
    	<action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>
<activity
	android:name=".launchmode.SecondActivity"
    android:launchMode="singleInstance"/>
<activity android:name=".launchmode.ThirdActivity"
public class FirstActivity extends AppCompatActivity {

    private static final String TAG = "launch_FirstActivity";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_first);
        //打印当前活动的实例
        Log.d(TAG, "Task id is"+ getTaskId());
        Button btn = findViewById(R.id.btn_first);
        btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
                startActivity(intent);
            }
        });
    }
}
public class SecondActivity extends AppCompatActivity {

    private static final String TAG = "launch_SecondActivity";
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);
        Log.d(TAG, "Task id is" + getTaskId());
        Button btn = findViewById(R.id.button1);
        btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(SecondActivity.this, ThirdActivity.class);
                startActivity(intent);
            }
        });
    }
}
public class ThirdActivity extends AppCompatActivity {

    private static final String TAG = "launch_ThirdActivity";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_third);
        Log.d(TAG, "Task id is" + getTaskId());
    }
}
  • logcat结果
  • android系统通过任务栈 android任务栈特点_任务栈_14

  • 说明:在FirstActivity中点击按钮进入SecondActivity中,再从SecondActivity中点击按钮进入ThirdActivity,可以看到打印出来的Task id的信息,FirstActivity和ThirdActivity的Task id一样,是存放在同一个返回栈中,SecondActivity的Task id不同,是存放在另一个返回栈中。

  • 示意图(启动和返回)
  • android系统通过任务栈 android任务栈特点_任务栈_15

五、用到的填坑方式六、注释


  1. taskAffinity:控制Activity所属的任务栈。
    方式一:配合launchMode=singleTask或者singleInstance使用。
    方式二:首先在activity中设置TaskAffinity属性,然后在启动Activity时设置flag为FLAG_ACTIVITY_NEW_TASK。这样可以让某些Activity会在taskAffinity指定的栈中启动。 ↩︎