Activity的介绍

一、 典型情况下Activity的生命周期:

Activity的介绍_第1张图片

  1. onCreateonDestroy是配对的,分别表示着Activity的创建和销毁,并且只可能有一次调用。
  2. onStartonStop是配对的,是从Activity是否可见这个角度来回调的。(可见了,但没有出现在前台,我们还看不到)
  3. onResumeonPause是从Activity是否位于前台这个角度来回调的。
  4. onRestart,表示Activity正在重新启动,当前Activity从不可见重新变为可见状态时,onRestart就会被调用。
  5. 旧的Activity执行完onPause之后,新的Activity才能onResume

二、 异常情况下Activity的生命周期:

1. 系统配置发生改变导致Activity被杀死并重新创建。

Activity的介绍_第2张图片

  • 当系统配置发生改变后(系统字体、屏幕方向、用户界面模式,等等),Activity会被销毁,其onPauseonStoponDestroy均会被调用;
  • Activity在异常情况下终止时,系统会调用onSaveInstanceState来保存当前Activity的状态(在正常的情况下,系统不会回调这个方法);
  • 当Activity被重新创建后,系统会调用onRestroreInstanceState,并且把Activity销毁时onSaveInstanceState方法所保存的Bundle对象作为参数同时传递给onRestoreInstanceStateonCreate方法。(先onCreateonRestoreInstanceState,官方推荐用onRestoreInstanceState
  • 默认情况下,每个Activity、每个View都有onSaveInstanceStateonRestoreInstanceState,查看它们的具体实现就知道系统会自动保存View的哪些数据。
阻止因某项配置发生改变Activity会被重新创建的方法:

AndroidMainifest.xml中加入Activity的声明:

android:configChanges = "orientation|keyboardHidden"

以上只是把orientationkeyboardHidden锁定,当触发时会回调onConfigurationChanged(可在Activity重写)方法来代替onSaveInstanceState

完整代码可以是这样:


<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.test20190122">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

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

manifest>

2. 资源内存不足导致低优先级的Activity被杀死

Activity的优先级:

  1. 前台Activity(优先级最高)
  2. 可见但非前台Activity(比如Activity中弹出的对话框)
  3. 后台Activity(已经被暂停的Activity,优先级最低)
    但系统内存不足时,系统就会按照上述优先级去杀死目标Activity所在的进程,并在后续通过onSaveInstanceStateonRestoreInstanceState来存储和回复数据。
  4. 如果一个进程中没有四大组件在执行,那么这个进程很快会被系统杀死。比较好的方法是将后台工作放入Service中,从而保证进程有一定的优先级。

三、 Activity的启动模式:

任务栈是一种“后进先出”的栈结构,每按一下back键,就会有一个Activity出栈,直到栈空位置,当栈中无任何Activity时,系统就会回收这个任务栈。

1.standard:标准模式

  • (系统默认的模式)
  • 每次启动一个Activity都会重新创建一个新的实例,不管这个实例是否已经存在。 (创建实例时,它的onCreateonStartonResume都会被调用)
  • 在此模式下,谁启动了这个Activity,那么这个Activity就运行在启动它的那个Activity所在的栈中。
  • ApplicationContext去启动standard模式的Activity的时候会报错,因为非Activity类型的Context(如ApplicationContext)并没有所谓的任务栈。解决的方法是为待启动的Activity指定FLAG_ACTIVITY_NEW_TASK标记位,这样启动的时候就会为它创建一个新的任务栈。

2.singleTop:栈顶复用模式

  • 在这种模式下,如果新Activity已经位于任务栈的栈顶,那么此Activity不会被重新创建,同时它的onNewIntent方法会被回调(此方法可被重写,通过它的参数可以取出当前请求的信息)。
  • 如果新Activity的实例已存在但不是位于栈顶,那么新Activity仍然会重新重建。

3.singleTask:栈内复用模式

  • 只要Activity在一个栈中存在,那么多次启动此Activity都不会重新创建实例。同时它的onNewIntent方法会被回调。
  • 系统首先会寻找是否存在Activity想要的任务栈,如果不存在,就重新创建一个任务栈,然后创建Activity的实例并放到栈中。
  • 如果存在Activity所需要的任务栈:(1)如果此栈中有Activity的实例存在,那么系统就会把Activity调到栈顶并调用它的onNewIntent方法。(2)如果实例不存在,就创建Activity的实例并把Activity压入栈中。
  • singleTask默认具有clearTop的效果,会导致栈内所有在Activity的实例上面的Activity全部出栈。

4.singleInstance:单实例模式

  • 具有singleTask模式的所有特性。
  • 此种模式的Activity只能单独地位于一个任务栈中。

任务栈分为前台任务栈和后台任务栈,后台任务栈中的Activity位于暂停状态,用户可以通过切换将后台任务栈再次调到前台。
Activity的介绍_第3张图片
Activity的介绍_第4张图片

给Activity指定启动模式的方法:(2个)

1. 通过AndroidMenifest.xml为Activity指定启动模式。

2. 通过在Intent中设置标志位来为Activity指定启动模式。
Intent intent = new Intent();
        intent.setClass(MainActivity.this,SecondActivity.class);
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        startActivity(intent);
3. 两种方法的区别:
  1. 第二种方式的优先级要高于第一种,当两种同时存在时,以第二种方式为准。
  2. 两种方法在限定范围上有所不同。(…)

Activity的Flags:

可用来设定Activity的启动模式,可用来影响Activity的运行状态。

FLAG_ACTIVITY_NEW_TASK

为Activity指定“singleTask”启动模式。

FLAG_ACTIVITY_SINGLE_TOP

为Activity指定“singleTop”启动模式。

FLAG_ACTIVITY_CLEAR_TOP

具有此标记位的Activity,当它启动时,在同一个任务栈中所有位于它上面的Activity都要出栈。(一般配合FLAG_ACTIVITY_NEW_TASK使用)

FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS

具有这个标记的Activity不会出现在历史Activity的列表中。(等用于在xml中指定Activity的属性android:excludeFromRecents="true"

四、 IntentFilter的匹配规则:

隐式调用启动Activity需要Intent能够匹配目标组件的IntentFilter中所设置的过滤信息。IntentFilter中的过滤信息有action、category、data。

一个Intent同时匹配action、category、data才算完全匹配,只有完全匹配才能启动目标Activity。
一个Activity中可以有多个intent-filter,一个Intent只要能匹配任何一组intent-filter即可启动对应的Activity。

示例:

<activity
            android:name=".SecondActivity"
            android:configChanges="screenLayout"
            android:label="@string/app_name">
            <intent-filter>
                <action android:name="com.example.test20190122.c"/>
                <action android:name="com.example.test20190122.d"/>
                <category android:name="com.example.test20190122.category.c"/>
                <category android:name="com.example.test20190122.category.d"/>
                <category android:name="android.intent.category.DEFAULT"/>
                <data android:mimeType="text/plain"/>
            intent-filter>
        activity>

1. action的匹配规则

  • 一个过滤规则中可以有多个action,只要Intent中的action能够和过滤规则中的任何一个action相同即可匹配成功。匹配是指action的字符串值完全一样;
  • Intent中如果没有指定action,那么匹配失败;
  • action区分大小写。

2. category的匹配规则:

  • 系统预定义了一些category,也可以自己定义category;
  • Intent中可以没有category,因为startActivitystartActivityForResult会默认为Intent加上android.intent.category.DEFAULT
  • 基于第二点⬆,为了activity能够接收隐式调用,必须在intent-filter中指定android.intent.category.DEFAULT
  • 一旦Intent中有category,不管有几个,每个都要能够和过滤规则中的任何一个category相同;

3. data的匹配规则:

  • 如果过滤规则中定义了data,那么Intent中必须也要定义可匹配的data;
  • data的语法:
<data
    android:mimeType="string"
    android:scheme="string"
    android:host="string"
    android:port="string"
    android:path="string"
    android:pathPattern="string"
    android:pathPrefix="string" />
  • data由两部分组成,mimeTypeURImimeType指媒体类型(比如image/jpeg、audio/mpeg4-generic、video/*等),

URI的结构:

<scheme>://<host>:<port>/[<path>|<pathPrefix>|<pathPattern>]

URI例子:

content://com.example.project:200/folder/subfolder/etc
http://www.baidu.com:80/search/info

scheme:URI的模式,比如,http、file、content等;
host:URI的主机名,比如,www.baidu.com;
port:URI的端口号,比如,80;
pathpathPatternpathPrefix:这三个参数表述路径信息。path表示完整的路径信息;pathPattern也表示完整的路径信息,它可以包含通配符“*”,“*”表示0个或多个任意字符。pathPrefix表示路径的前缀信息。

  • 如果inten-filter指定了mimeType,却没有指定URIURI的的默认值为contentfile
  • 如果要为Intent指定完整的data,必须调用setDataAndType方法,不能先调用setDate再调用setType,因为这两个方法彼此会清楚对方的值;

例如:

intent.setDataAndType(Uri.parse("file://abc"),"image/png");
  • data的特殊写法:(以下两种写法作用一样)
<intent-filter>
	<data android:mimeType="file" android:host="www.baidu.com"/>
	...
intent-filter>

<intent-filter>
	<data android:mimeType="file"/>
	<data android:host="www.baidu.com"/>
	...
intent-filter>            

4.intent-filter完全匹配的Intent示例:

Intent intent = new Intent("com.example.test20190122.a");
intent.addCategory("com.example.test20190122.b");
intent.setDataAndType(Uri.parse("file://abc"),"text/plain");
startActivity(intent);

5.Intent-filter的匹配规则对于Service和BroadcastReceiver同样适用。但系统建议用显示调用方式来启动服务(Service)。

6.查看是否有Activity能够匹配隐式Intent的方法:

  • PackageManagerresolveActivity方法或者IntentresolveActivity方法。(它们找不到匹配的Activity就会返回null)
  • resolveActivity能够返回最佳匹配的Activity信息,而PackageManagerqueryIntentActivitis能返回所有成功匹配的Activity信息。
  • queryIntentActivitisresolveActivity的原型是:
public abstract List<ResolveInfo> queryIntentActivities(Intent intent,int flags);
public abstract ResolveInfo resolveActivity(Intent intent,int flags);

第二个参数,如果使用MATCH_DEFAULT_ONLY这个标记位,就仅仅匹配在intent-filter中声明了这个category的Activity。这个标记位的意义在于,只要上述两个方法不返回null,那么startActivity一定可以成功。因为不含有DEFAULT这个category的Activity是无法接收隐式Intent的。

  • 有一类action和category比较重要:
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />

这两者的共同作用是用来标明这是一个入口Activity,并且会出现在系统的应用列表中,但少了任何一个都没有实际意义。

你可能感兴趣的:(Android,Android,Studio,《Android开发艺术探索》)