onSaveInstanceState-->onPause-->onStop-->onDestroy-->onCreate-->onStart-->onRestoreInstanceState-->onResume-->
onSaveInstanceState-->onPause-->onStop-->onDestroy-->onCreate-->onStart-->onRestoreInstanceState-->onResume-->onSaveInstanceState-->onPause-->onStop-->onDestroy-->onCreate-->onStart-->onRestoreInstanceState-->onResume-->
5、修改AndroidManifest.xml,把该Activity添加 android:configChanges="orientation",执行步骤3
onSaveInstanceState-->onPause-->onStop-->onDestroy-->onCreate-->onStart-->onRestoreInstanceState-->onResume-->
onSaveInstanceState-->onPause-->onStop-->onDestroy-->onCreate-->onStart-->onRestoreInstanceState-->onResume-->onConfigurationChanged-->
7、把步骤5的android:configChanges="orientation" 改成 android:configChanges="orientation|keyboardHidden",执行步骤3,就只打印onConfigChanged
2、设置Activity的android:configChanges="orientation"时,切屏还是会重新调用各个生命周期,切横、竖屏时只会执行一次
3、设置Activity的android:configChanges="orientation|keyboardHidden"时,切屏不会重新调用各个生命周期,只会执行onConfigurationChanged方法
ActivityActivity的生命周期不会有改变运行时按下HOME键(跟被完全覆盖是一样的):onSaveInstanceState --> onPause --> onStop onRestart -->onStart--->onResume
Activity的启动模式
- standard:标准模式
系统的默认模式,每次启动一个Activity都会重新创建一个新的实例,不管这个实例是否已经存在。被创建的生命周期符合典型情况下的生命周期,它的onCreate、onStart、onResume都会调用。在这种模式下,谁启动了这个Activity,那么这个Activity就运行在启动它的那个Activity栈中。比如Activity A启动了Activity B(B是标准模式),那么B就会进入到A所在的栈中。使用场景大多数Activity。 - singleTop:栈顶复用模式
如果新Activity已经位于任务栈的栈顶,那么次Activity不会被重新创建,同时它的onNewIntent方法会被回调,通过此方法我们可以取出当前请求的信息。这个Activity的onCreate、onStart不会被调用,因为它并没有发生改变。使用场景如新闻类或者阅读类App的内容页面。 - singleTask:栈内复用模式
一种单实例模式,只要Activity在一个栈中存在,多次启动Activity都不会重新创建实例,系统会回调onNewIntent方法。当设置此模式后,比如Activity A会首先寻找是否存在A想要的任务栈,如果不存在就重新创建一个任务栈,如果存在,就看A是否在栈中有实例存在,如果有实例存在那么系统就会把A调到栈顶并调用onNewIntent方法,同时由于singleTask默认具有clearTop的效果,就会导致栈内所有在A上面的Activity全部出栈,如果不存在,就创建A的实例并把A压入栈中。使用场景如浏览器的主界面。不管从多少个应用启动浏览器,只会启动主界面一次,其余情况都会走onNewIntent,并且会清空主界面上面的其他页面。 - singleInstance:单实例模式
这是一种加强的singleTask模式,除了具有singleTask所有特性外,还具有此种模式的Activity A只能单独的位于一个新的任务栈,然后A单独在这个栈中,由于栈内复用的特性,后续的请求均不会创建新的Activity。使用场景如闹铃提醒,将闹铃提醒与闹铃设置分离。singleInstance不要用于中间页面,如果用于中间页面,跳转会有问题,比如:A -> B (singleInstance) -> C,完全退出后,在此启动,首先打开的是B。 - Activity的Flags
- 设置启动模式的两种方式
通过AndroidMenifest为Activity指定启动模式
android:launchMode="singleTask"
Intent中设置标记为来为activity指定启动模式
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
- 常用标记位
FLAG_ACTIVITY_NEW_TASK
为Activity指定singleTask启动模式
FLAG_ACTIVITY_SINGLE_TOP
为Activity指定singleTop启动模式
FLAG_ACTIVITY_CLEAN_TOP
具有此标记位的Activity,当它启动时,同一个任务栈中所有位于它上面的Activity都要出栈。
FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
不希望用户通过历史列表回到我们的Activity的时候这个标记比较有用,等同于在XML中指定Activity的属性android:excludFromRecents="true"
.
3. IntentFilter的匹配规则
为了匹配过滤列表,需要同时匹配过滤列表中的action、category、data信息,否则匹配失效。一个过滤列表中的action、category和data可以有多个。一个Intetn同时匹配action类别、category类别、data类别才算完全匹配,只有完全匹配才能启动目标Activity。一个Activity中可以有多个intent-filter,一个Intent只要匹配其中任何一组intent-filter即可成功启动对应的Activity。
1. action的匹配规则
action是一个字符串,系统预定义了一些action,我们也可以自定义action,匹配规则是Intent中的action必须能够和过滤规则中的action匹配,一个过滤规则中可以有多个action,那么只要Intent中的action能够和过滤规则中的任何一个action相同即可匹配成功,Intent中的action存在且必须和过滤规则中的其中一个action相同。
2. category的匹配规则
category是一个字符串,系统预定义了一些category,我们也可以在应用中定义自己的category。category和action的匹配规则不同,要求Intent中如果含有category,那么所有的category都必须和过滤规则中(即intent filter中设置的category)的其中一个相同。Intent也可以没有category,如果没有category的话,在startActivity或者startActivityForResult的时候会默认为Intent加上"android.intent.category.DEFAULT"
。
3. data的匹配规则
如果过滤规则中添加了data,那么Intent中必须也要定义可匹配的data。data的语法如下所示:
<code class="hljs haskell has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"> <<span class="hljs-typedef" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">data</span> </span>
android:scheme=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"string"</span>
android:host=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"string"</span>
android:port=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"string"</span>
android:path=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"string"</span>
android:pathPattern=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"string"</span>
android:pathPrefix=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"string"</span>
android:mimeType=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"string"</span> /></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li></ul>
data由两部分组成,mineType和URI。mineType指媒体类型,比如image/jpeg、audio/mpeg4-generic和video/*等,可以表示图片、文本、视频等不同媒体格式,而URI包含的数比较多,一个URI结构如下所示
<code class="hljs ruby has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><scheme><span class="hljs-symbol" style="color: rgb(0, 102, 102); box-sizing: border-box;">://<host></span><span class="hljs-symbol" style="color: rgb(0, 102, 102); box-sizing: border-box;">:<port>/</span>[<path>|<pathPrefix>|<pathPattern>]</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul>
下面举个实际的例子大家就明白了:
<code class="hljs avrasm has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-label" style="box-sizing: border-box;">content:</span>//<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">com</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.example</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.project</span>:<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">200</span>/folder/subfolder/etc</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul>
其中:
- Scheme:URI的模式,比如http、file、content等,如果URI中没有指定scheme,那么整个URI的其他参数无效,即URI也是无效的;
- Host:URI的主机名,如com.example.project,如果host未指定,那么整个URI中的其他参数无效,即URI也是无效的;
- Port:URI中的端口号,如200,只有URI中指定了scheme和host参数的时候port参数才有意义;
- Path、PathPattern和PathPrefix:这三个参数表示路径信息,如folder/subfolder/etc,其中path表示完整的路径信息;PathPattern也表示完整的路径信息,但是它里面可包含通符“*”,表示0个或多个任意字符;PathPrefix表示路径的前缀信息。
data匹配规则:
<code class="hljs r has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"> <intent-filter>
<data android:mimeType=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"image/*"</span>/>
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">...</span>
</intent-filter></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li></ul>
这种规则制定了媒体类型为所有类型的图片,那么Intent中mimeType属性必须为”image/*”才能匹配,这种情况下没有指定URI,但是Intent中的URI部分的schema必须为content或者file才能匹配,我们需要在Intent中这样指定:
intent.setDataAndType(Uri.parse("file://abc"), "image/png")
如果要为Intent指定完整的data,必须要调用setDataAndType方法,不能先调用setData再调用setType,因为这两个方法彼此会清除对方的值。
怎么判断是否有Activity是否能够匹配我们的隐式Intent?
1. 采用PackageManager
的resolveActivity
方法或者Intent的resolveActivity
方法,如果找不到就返回null。
2. PackageManager
方法还提供了queryIntentActivities
方法,这个方法和resolveActivity
方法最大的不同是,它不是返回最佳匹配的Activity的信息,而是返回的是所有成功匹配的Activity信息。我们可以看一下方法的原型:
<code class="hljs cs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">abstract</span> List<ResolveInfo> <span class="hljs-title" style="box-sizing: border-box;">queryIntentActivities</span>(Intent intent,@ResolveInfoFlags <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> flags);
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">abstract</span> ResolveInfo <span class="hljs-title" style="box-sizing: border-box;">resolveActivity</span>(Intent intent, @ResolveInfoFlags <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> flags);</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li></ul>
上述两个方法的第二个参数注意,我们要使用MATCH_DEFAULT_ONLY
这个标记位,只能匹配intent-filter
中声明了<category android:name="android.intent.category.DEFAULT"/>
这个category的Activity。使用这个标记位最大的意义是上述两个方法不返回null,那么startActivity一定可以成功。如果不使用这个标记位,就可以吧intent-filter
中category不含DEFAULT的那些Activity匹配出来,startActivity有可能失败,不含有DEFAULT这个category的Activity是无法接受隐式Intent的。
3. 在action和category中有一类比较重要,用来标注一个入口:
<code class="hljs xml has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: border-box;"><<span class="hljs-title" style="box-sizing: border-box; color: rgb(0, 0, 136);">action</span> <span class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0, 102);">android:name</span>=<span class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 0);">"android.intent.action.MAIN"</span> /></span>
<span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: border-box;"><<span class="hljs-title" style="box-sizing: border-box; color: rgb(0, 0, 136);">category</span> <span class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0, 102);">android:name</span>=<span class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 0);">"android.intent.category.LAUNCHER"</span> /></span></code>