<commit_before>---

layout: post
title: Android四大组件之Activity的组织与管理
image:http://upload-images.jianshu.io/upload_images/1460468-36db25ce302017c8.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240

---

面试的时候，面试官经常跟你随便侃侃Activity的启动模式，但Activity启动牵扯的知识点其实很多，并非能单单用四个启动模式就能概括的，默认的启动模式的表现会随着Intent Flag的设置而改变，因此侃Activity启动模式大多走流程装逼，最多结合项目遇到的问题，随便刁难一下面试者，并不太容易把控，也许最后，面试官跟面试者的答案都是错了，比如在Service中必须通过设置FLAG_ACTIVITY_NEW_TASK才能启动Activity，这个时候启动Activit会有什么样的表现呢？就这一个问题，答案就要分好几个场景：

* Activity的taskAffinity属性的Task栈是否存在
* 如果存在，要看Activity是否存已经在其taskAffinity的Task
* 如果在其taskAffinity的Task，要看是不是其rootActivity
* 如果是其rootActivity，要看启动该Activity的Intent是否相等

不同场景，所表现的行为都会有所不同，再比如singleInstance属性，如果设置了，大家都知道只有一个实例，将来再启动会复用，但是如果使用Intent.FLAG_ACTIVITY_CLEAR_TASK来启动的时候，其实会重建，并非完全遵守singleInstance的说明，还有不同Flag在叠加使用时候也会有不同的表现，单一而论Activity启动模式其实是很难的。本文也仅仅是涉及部分启动模式及Flag，更多组合跟场景要自己看源码或者实验来解决了。

## 简单基本launchmode

本文假定大家对于Activity的Task栈已经有初步了解，首先，看一下Activity常见的四种启动模式及大众理解，这也是面试时最长问的：

* standard：标准启动模式（默认启动模式），每次都会启动一个新的activity实例。
* singleTop：单独使用使用这种模式时，如果**Activity实例位于当前任务栈顶**，就重用栈顶实例，而不新建，并回调该实例onNewIntent()方法，否则走新建流程。
* singleTask：这种模式启动的Activity**只会存在相应的Activity的taskAffinit任务栈中**，同一时刻系统中只会存在一个实例，已存在的实例被再次启动时，会重新唤起该实例，并清理当前Task任务栈该实例之上的所有Activity，同时回调onNewIntent()方法。
* singleInstance：这种模式启动的Activity独自占用一个Task任务栈，同一时刻系统中只会存在一个实例，已存在的实例被再次启动时，只会唤起原实例，并回调onNewIntent()方法。

需要说明的是：**上面的场景仅仅适用于Activity启动Activity，并且采用的都是默认Intent，没有额外添加任何Flag**，否则表现就可能跟上面的完全不一致，尤其要注意的是FLAG_ACTIVITY_NEW_TASK的使用，后面从源码中看，依靠FLAG_ACTIVITY_NEW_TASK其实可以分为两派。

## Intent.FLAG_ACTIVITY_NEW_TASK分析

从源码来看，Intent.FLAG_ACTIVITY_NEW_TASK是启动模式中最关键的一个Flag，依据该Flag启动模式可以分成两类，设置了该属性的与未设置该属性的，对于非Activity启动的Activity（比如Service或者通知中启动的Activity）需要显示的设置Intent.FLAG_ACTIVITY_NEW_TASK，而singleTask及singleInstance在AMS中被预处理后，隐形的设置了Intent.FLAG_ACTIVITY_NEW_TASK，而启动模式是standard及singletTop的Activity不会被设置Intent.FLAG_ACTIVITY_NEW_TASK，除非通过显示的intent setFlag进行设置。
<commit_msg>Activity启动模式<commit_after>---
layout: post
title: Android四大组件之Activity的组织与管理

---

面试的时候，面试官经常跟你随便侃侃Activity的启动模式，但Activity启动牵扯的知识点其实很多，并非能单单用四个启动模式就能概括的，默认的启动模式的表现会随着Intent Flag的设置而改变，因此侃Activity启动模式大多走流程装逼，最多结合项目遇到的问题，随便刁难一下面试者，并不太容易把控，也许最后，面试官跟面试者的答案都是错了，比如在Service中必须通过设置FLAG_ACTIVITY_NEW_TASK才能启动Activity，这个时候启动Activit会有什么样的表现呢？就这一个问题，答案就要分好几个场景：

* Activity的taskAffinity属性的Task栈是否存在
* 如果存在，要看Activity是否存已经在其taskAffinity的Task
* 如果在其taskAffinity的Task，要看是不是其rootActivity
* 如果是其rootActivity，要看启动该Activity的Intent是否相等

不同场景，所表现的行为都会有所不同，再比如singleInstance属性，如果设置了，大家都知道只有一个实例，将来再启动会复用，但是如果使用Intent.FLAG_ACTIVITY_CLEAR_TASK来启动的时候，其实会重建，并非完全遵守singleInstance的说明，还有不同Flag在叠加使用时候也会有不同的表现，单一而论Activity启动模式其实是很难的。本文也仅仅是涉及部分启动模式及Flag，更多组合跟场景要自己看源码或者实验来解决了。

## 简单基本launchmode

本文假定大家对于Activity的Task栈已经有初步了解，首先，看一下Activity常见的四种启动模式及大众理解，这也是面试时最长问的：

* standard：标准启动模式（默认启动模式），每次都会启动一个新的activity实例。
* singleTop：单独使用使用这种模式时，如果**Activity实例位于当前任务栈顶**，就重用栈顶实例，而不新建，并回调该实例onNewIntent()方法，否则走新建流程。
* singleTask：这种模式启动的Activity**只会存在相应的Activity的taskAffinit任务栈中**，同一时刻系统中只会存在一个实例，已存在的实例被再次启动时，会重新唤起该实例，并清理当前Task任务栈该实例之上的所有Activity，同时回调onNewIntent()方法。
* singleInstance：这种模式启动的Activity独自占用一个Task任务栈，同一时刻系统中只会存在一个实例，已存在的实例被再次启动时，只会唤起原实例，并回调onNewIntent()方法。

需要说明的是：**上面的场景仅仅适用于Activity启动Activity，并且采用的都是默认Intent，没有额外添加任何Flag**，否则表现就可能跟上面的完全不一致，尤其要注意的是FLAG_ACTIVITY_NEW_TASK的使用，后面从源码中看，依靠FLAG_ACTIVITY_NEW_TASK其实可以分为两派。

## Intent.FLAG_ACTIVITY_NEW_TASK分析

从源码来看，Intent.FLAG_ACTIVITY_NEW_TASK是启动模式中最关键的一个Flag，依据该Flag启动模式可以分成两类，设置了该属性的与未设置该属性的，对于非Activity启动的Activity（比如Service或者通知中启动的Activity）需要显示的设置Intent.FLAG_ACTIVITY_NEW_TASK，而singleTask及singleInstance在AMS中被预处理后，隐形的设置了Intent.FLAG_ACTIVITY_NEW_TASK，而启动模式是standard及singletTop的Activity不会被设置Intent.FLAG_ACTIVITY_NEW_TASK，除非通过显示的intent setFlag进行设置。

{'fraction_non_alphanumeric': 0.07352143244709712, 'fraction_numerical': 0.00705371676614216, 'mean_word_length': 27.8046875, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7154627', 'n_tokens_mistral': 2434, 'n_tokens_neox': 2711, 'n_words': 45}