美文网首页
Activity的生命周期和启动模式笔记

Activity的生命周期和启动模式笔记

作者: ZjyMac | 来源:发表于2018-02-28 19:14 被阅读0次

    一,Activity生命周期全面分析

    (1)onCreate()
    表示Activity正在被创建,主要做初始化工作例如加载界面布局资源,初始化所需数据。
    (2)onRestart()
    当前Activity 的 onPause()和onStop()被执行了 ,之后又回到了这个Activity会被调用
    (3)onStart()
    当前Activity已经可见,但是还没出现在前台及还无法和用户进行交互(也可理解为已经显示但用户还看不到)
    (4)onResume()
    当前Activity已经可见也可以与用户进行交互,与onStart()的区别在于 onResume处于前台,onStart()处于后台
    (5)onPause()
    当前Activity表示处于暂停状态,之后会调用onStop(),这里可以做一些不太耗时的操作,例如停止动画,存储数据等,这里要注意只有当前Activity走完onPause()方法 新的Activity才会执行onResume(极端情况下也有可能出现走到Pause方法立刻回到当前activity这个时候会走onResume)
    (6)onStop()
    当前Activity即将停止,可以做一写回收工作尽量避免过多的耗时操作
    (7)onDestroy()
    当前Activity即将被销毁,可以做回收工作和最终的资源释放

    这里写图片描述
    • 注:当新打开的Activity主题为透明,则旧的Activity不会调用onStop()

    问题:为什么 当前Activity走完onPause()方法 新的Activity才会执行onResume()方法?
    答:启动Activity的请求会由Instrumentationlai来处理,它通过Binder向AMS(ActivityManagerService)发起请求,AMS内部维护一个ActivityStack并负责栈内的Activity的状态同步,AMS通过ActivityThread去同步Activity的状态从而完成生命周期方法的调用,在ActivityStack中的resumeTipActivity-InnerlLock方法中 会判断栈顶的Activity 需要onPause后新的Activity才可以启动,启动后ActivityThread中的ApplicationThread调用scheduleLaunchActivity方法完成新的Activity的onCreate,onStart,onResume方法。

    二,异常情况生命周期分析

    • 情况一:资源相关的系统配置发生改变,导致Activity被杀死并且重新创建

    例如横竖屏切换如果不做特殊处理,Activity就会被销毁并且重新创建,这个时候当销毁的时候会调用onSaveInstanceState()方法,重新创建会调用onRestoreInstanceState()。在这两个方法中系统会自动做一些恢复工作,例如文本框用户输入的数据,listview滚动的位置等。
    系统自动恢复View工作的原理:
    当Activity被意外终止后,Activity会调用onSaveInstanceState去保存数据,然后Activity会委托window去保存数据,接着window再委托顶级的容器view去保存数据,顶级容器是一个ViewGroup一般来说很可能是DecorView 之后顶层容器再去一一通知它的子元素来保存数据,是一种委托思想上层委托下层,android中view绘制,事件分发都是类似的思想。
    保存时我们会在onSaveInstanceState中进行操作,当获取的时候我们可以在onCreate或者onRestoreInstanceState()中获取。
    二者区别:
    当onRestoreInstanceState被调用,其参数一定有值,不用额外去判断空值。onCreate就需要先去判断其参数是否为空再进行后续操作。

    系统只在Activity异常终止的时候才会调用onSaveInstanceState与onRestoreInstanceState来储存和恢复数据,其他情况不会触发这个过程。但是按Home键或者启动新Activity仍然会单独触发onSaveInstanceState的调用。”

    • 情况二:资源内存不足导致低优先级的Activity被杀死

    Activity优先级排序(由高到低)
    1.前台Activity:正在和用户交互的Activity,优先级最高
    2.可见非前台Activity:例如弹出对话框的Activity·,可见但是无法和用户直接交互
    3.后台Activity:已经被暂停的Activity,比如执行了onStop()

    • 为Activity设置configChanges属性
    <activity
                android:name=".MainActivity"
                android:configChanges="orientation|screenSize" />
    

    参数说明:
    “mcc“ 移动国家号码,由三位数字组成,每个国家都有自己独立的MCC,可以识别手机用户所属国家。
    “mnc“ 移动网号,在一个国家或者地区中,用于区分手机用户的服务商。
    locale“ 所在地区发生变化,一般指切换系统语言
    “touchscreen“ 触摸屏已经改变。(这不应该常发生,可以忽略)
    “keyboard“ 键盘模式发生变化,例如:用户接入外部键盘输入。
    "keyboardHidden" 键盘的可访问性发生变化——例如:用户发现了硬件键盘。
    “navigation“ 导航型发生了变化。(这不应该常发生。)
    "screenLayout" 屏幕布局发生变化——这个会导致显示不同的Activity。
    "fontScale" 字体缩放因子发生变化——用户选择了新的字体大小。
    "uiMode" 当UI模式发生改变的时候——当用户放置设备到桌子或/汽车或夜间模式改变的时候可以引起UI模式变化。阅读UiModeManager。在API级别8时引入。
    "orientation" 屏幕方向发生变化——用户旋转了屏幕。注意:如果应用程序的目标API级别是13或更高(通过属性minSdkVersion和属性targetSdkVersion声明),你也需要声明配置项screenSize,因为这将在设备选择肖像和屏幕方向时发生改变。
    "screenSize" 当前可用屏幕大小发生变化。这代表一个当前可用大小的变化,和当前的比率相关,因此当用户选择不同的画面和图像,会发生变化。然而,如果你的程序目标API级别是12或更低,你的Activity总是会自己处理这个配置变化(这个变化不会引起Activity的重启,甚至在Android 3.2或更新的设备上)。在API级别13里加入的。
    "smallestScreenSize" 物理屏幕大小的变化。不管方向的变化,仅仅在实际物理屏幕打包变化的时候,如:外接显示器。这个配置项的变化引起在smallestWidth configuration里的变化。然而,如果你的程序目标API级别是12或更低,你的Activity将自己处理这个变化(这个变化不会引起Activity的重启,甚至在Android 3.2或更新的设备上)在API级别13里加入的。

    三,启动模式

    • Activity的LaunchMode
      (1)standard标准模式
      每次启动都会重现创建一个新的实例,不管这个实例是否存在,被创建的实例的生命周期符合典型情况下的Activity的生命周期。
      当我们用ApplicationContext去启动standard模式的Activity回报错,原因是,该模式下之后在启动的Activity会自动默认进入启动他的Activity所属的任务栈中,所以非Activity类型的Context并没有所谓的任务栈所以就会产生问题,解决这个问题可以通过制定FLAG_ACTIVITY_NEW_TASK标记为,这样会创建一个新的任务栈,这种情况下相当于以singleTask模式启动的。
      (2)singleTop:栈顶复用模式
      如果启动的Activity位于任务栈的栈顶,则不会重新创建,同时会调用他的onNewIntent()方法,通过此方法的参数可以获取到当前请求的信息。如果新的Acvtivity已经存在但是不在栈顶,那么新的Activity仍然会重新创建。
      (3)singleTask栈内复用模式
      只要Activity在一个栈中存在,那么多次启动此Activity都不会重新创建实例,也会回调起onNewIntent() 。并且将其调到栈顶,在其上方的对象都会被销毁。具体来说首先系统乎现寻找是否存在该Activity素偶需要的任务栈,如果不存在先建立任务栈,在创建该Activity的实例并存放在栈中,如果存在当前Activity所需要的任务栈,则要看是否在这个栈中存在其实例,如果存在则将其调到栈顶并且调用onNewIntent()方法,如果不存在则创建其实例,并将其压入栈中。
      (4)singleInstance单例模式
      加强版的singleTask模式,这种模式的Activity会单独存储在一个任务战中,后续均不会产生新的实例除非任务栈被系统销毁

    • 任务栈:TaskAffinity
      默认情况下,所有的Activity所需要的任务栈都为该应用的包名,我们可以为每一个Activity指定单独不同的任务栈,设置TaskAffinity属性,TaskAffinity主要和singleTask或者allowTaskReparenting属性配对使用
      另外任务栈主要分为前台任务栈和后台任务栈,后台任务栈的Activity处于暂停状态,yoghurt可以通过切换将后台任务栈再次调到前台。

    • 如何设置启动模式
      通过AndroidMenifest指定启动模式

    <activity
                android:name=".MainActivity"
                android:configChanges="orientation|screenSize"
                android:launchMode="singleTask"/>
    

    通过标志位指定启动模式

      Intent intent=new Intent();
            intent.setClass(this,IndexActivity.class);
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            startActivity(intent);
    
    • Activity的Flags
      (1) FLAG_ACTIVITY_NEW_TASK
      指定为singleTask启动模式
      (2)FLAG_ACTIVITY_SINGLE_TOP
      指定为singleTop启动模式
      (3)FLAG_ACTIVITY_CLEAR_TOP
      当通过这种方式启动时,在同一个任务栈中所有位于它上边的Activity都要出站,一般会和singleTask启动模式一起出现。在这种情况下,被启动的Activity如果存在实例,那么系统会调用它的onNewIntent,如果被启动的Activity采用standard方式,那么连同它以及它之上的Activity都要出栈,系统会创建新的放入栈顶。singleTask默认会具有此标记效果
      (4)FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
      等同于android:excludeFromRecents="true"
      具有这个标记的不会出现在历史Activity的类表中
    • IntentFilter的匹配规则
      android启动Activity分为两种 一种是隐式调用一种是显示调用
      系统提供的隐式调用:
     Intent intent = new Intent();
            //把打电话的动作ACTION_CALL封装至意图对象当中
            intent.setAction(Intent.ACTION_CALL);
            //设置打给谁
            intent.setData(Uri.parse("tel:" + phone));//这个tel:必须要加上,表示我要打电话。否则不会有打电话功能,由于在打电话清单文件里设置了这个“协议”
            //把动作告诉系统,启动系统打电话功能。
            startActivity(intent);
    

    自定义Activity,并隐式方式启动

    <activity android:name=".NextActivity">
        <intent-filter>
            <action android:name="com.itydl"/>
            <category android:name="android.intent.category.DEFAULT"/>
        </intent-filter>
    </activity>
    

    在<action>标签中我们指明了当前活动可以响应 com.itydl 这个 action,我们可以随便写里面的内容,它的加入表示给我们的Activity添加一个动作,只有带动作的Activity才能被隐式启动。而<category>标签则包含了一些附加信息,更精确地指明了当前的活动能够响应的 Intent 中还可能带有的 category。意图中设置的action必须跟"com.itydl"是完全匹配的,只有<action>和<category>中的内容同时能够匹配上 Intent中指定的 action和 category时,这个活动才能响应该 Intent。我们也道,android.intent.category.DEFAULT 是一种默认的 category,在调用startActivity()方法的时候会自动将这category添加到 Intent中

    对于Action的原理是:当StartActivity()运行的时候,该Activity会去系统所有清单文件中找对应的Action("")里面能匹配的Activity,找有没有对应的action与我们所写入的能匹配的,如果有(这里是NextActivity),这样就启动了NextActivity。

     Intent intent = new Intent();
            intent.setAction("com.itydl");
            startActivity(intent);
    

    添加Data

    <intent-filter>
        <action android:name="com.itydl"/>
        <data android:scheme="ydl"/>
        <category android:name="android.intent.category.DEFAULT"/>
    </intent-filter>
    

    在这里浅显介绍一下系统添加data下面的标签都有哪些:

    <data>标签中主要可以配置以下内容。

    1. android:scheme
      用于指定数据的协议部分。
    2. android:host
      用于指定数据的主机名部分。
    3. android:port
      用于指定数据的端口部分,一般紧随在主机名之后。
    4. android:path
      用于指定主机名和端口之后的部分,如一段网址中跟在域名之后的内容。
    5. android:mimeType
      用于指定可以处理的数据类型,允许使用通配符的方式进行指定。只有<data>标签中指定的内容和 Intent 中携带的 Data 完全一致时,当前活动才能够响应该 Intent。不过一般在<data>标签中都不会指定过多的内容,常见的是mimeType和scheme。
    intent.setData(Uri.parse("ydl:qwe"));
    

    相关文章

      网友评论

          本文标题:Activity的生命周期和启动模式笔记

          本文链接:https://www.haomeiwen.com/subject/tgumxftx.html