Android开发艺术探索 - 第1章 Activity的生命周期和启动模式

46 篇文章 0 订阅
39 篇文章 0 订阅
1. 生命周期
  1. 基本情况
    • onStart和onStop根据是否可见被回调;onResume和onPause根据是否在前台被回调。实际使用中没有其他区别。
    • onRestart当由不可见变为可见时回调。
    • 由A启动B,在A的onPause执行完之前,B不会被创建。所以在onPause中不能执行过多的操作。
  2. 异常情况
    设备配置改变或者内存不足时,Activity重建。
    • onSaveInstanceState & onRestoreInstanceState
      • 在onStop之前回调onSaveInstanceState保存状态,与onPause无绝对的先后顺序(Android P开始,发生在onStop之后);重建时在onStart之后回调onRestoreInstanceState恢复状态。
      • onSaveInstanceState在所有Activity重新返回时可能已经被销毁的情况下,都会被调用。所以,按home键/打开新Activity/锁屏操作,也会触发回调;onRestoreInstanceState只有在Activity真的被销毁重建时才被调用。
      • onCreate中也可以根据Bundle是否为空,进行数据恢复;onRestroeInstanceState被调用时Bundle一定不为空。
      • 每个View也实现了这两个回调,所以不同的View会有自己的默认保存和恢复操作。
    • android:configChanges指定希望去处理的一些configs,而不是让Activity重建。常见的如locale/orientation/screenSize/keyboardHidden,当这些configs改变时,Activity不会重建,而是回调onConfigurationChanged。screenSize为API 13引入,屏幕旋转时也会改变,所以要与orientation同时指定。
    • 内存不足时系统按照优先级去杀死目标Activity所在的进程。如果一个进程没有四大组件在执行,优先级会很低。
2. 启动模式

综合官方文档 Understand Tasks and Back Stack

  1. task和back stack
    • task是一系列Activity的集合,Activity通过back stack进行维护。
    • 当启动了新的task或者点击了home键,当前的task会被放置到background。
  2. launch mode
    定义了启动的Activity与当前task是如何关联的。两种方式指定:
    • 通过android:launchMode
      • standard
        创建一个新的Activity,运行在启动该Activity的Activity所在的task中。
      • singleTop
        如果要创建的Activity已经位于task的栈顶,仅回调该Activity的onNewIntent;否则创建新的Activity,无论在task中是否存在该Activity的实例。
      • singleTask
        check task name in taskAffinity
        if (task exist) {
            if (activity exist) {
                clearTop
                call onNewIntent
            } else {
                create activity and add to task
            }
        } else {
            create task
            create activity and add to task
        }
        
      • singleInstance
        在singleTask的基础上,限定了该Activity独占一个task。
    • 通过intent.addFlags。可以修改目标Activity launchMode中定义的行为。实际情况中,各种flag的组合加上launchMode的设置,最终的行为远比四种预设要复杂。
      • FLAG_ACTIVITY_NEW_TASK
        在新的task中(taskAffinity指定)启动该Activity。找到目标task之后,后续的行为则按照launchMode的设置处理。
        例如,Activity launchMode为standard,当intent中设置该flag,然后启动该Activity,则会在taskAffinity设置的task(此时一般是默认值)中创建该Activity,无论在该task中是否有其实例存在。
      • FLAG_ACTIVITY_SINGLE_TOP
        同singleTop。
      • FLAG_ACTIVITY_CLEAR_TOP
        • 会销毁目标Activity之上的所有Activity,之后的行为分两种情况:
          ①如果目标Activity是standard,则目标Activity销毁重建,新的intent会被传递进去。因为startand的Activity总是会被重建(官方解释)。
          ②如果目标Activity是其他mode,或者intent中指定了FLAG_ACTIVITY_SINGLE_TOP,则目标Activity不会被重建,通过onNewIntent传递新的intent
        • 当目标Activity为standard,与FLAG_ACTIVITY_NEW_TASK结合并不能实现singleTask的效果,因为standard的Activity会被重建。所以要另外加上FLAG_ACTIVITY_SINGLE_TOP才可以达到效果。
  3. activity的一些属性设置
    • taskAffinity:指定task name,默认值为package name。用于Application,指定所有Activity的task name;用于Activity,指定该Activity要运行的task的name。
    • allowTaskReparenting:允许Activity在其taskAffinity指定的task移到前台的时刻,从之前的task转移到该task。If an APK file contains more than one “app” from the user’s point of view, you probably want to use the taskAffinity attribute to assign different affinities to the activities associated with each “app”.
    • 其他见Clearing the back
    • Activity设置如下IntentFilter,会在启动器中显示图标,以提供task的入口:
      <intent-filter ... >
          <action android:name="android.intent.action.MAIN" />
          <category android:name="android.intent.category.LAUNCHER" />
      </intent-filter>
      
      对于singleTask和singleInstance的Activity可以添加该设置,方便用户启动相应的task。
3.IntentFilter

综合官方文档 Intents and Intent Filters & Intent & IntentFilter
Activity启动分显式和隐式。隐式需要Intent匹配目标Activity的IntentFilter,一个Activity可以有多个IntentFilter。
当系统接收到隐式Intent,会基于三个方面查找最合适的目标Activity:

  1. Action test
    filter可以声明0到多个action。
    Intent当中的action必须匹配filter其中一个,才能匹配。如果filter没有声明任何的action,则所有的Intent都不能匹配;如果Intent中没有指定action,则只要filter中至少有一个action就可以匹配。
  2. Category test
    filter可以声明0到多个category。
    Intent当中所有的category都能匹配于filter中的,则匹配。即Intent当中的category只要是filter中的category的子集,就可以匹配。
    如果Intent未指定category,startActivitystartActivityForResult会自动为Intent添加android.intent.category.DEFAULT,所以多数情况下filter中至少要定义该category才可以被隐式调用。
  3. Data test
    filter可以声明0到多个data。
    data包括两部分,URI和data type(MIME media type)。
    • URI结构如下:

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

      path/pathPrefix/pathPattern:path指完整路径;pathPattern可使用通配符;pathPrefix指示前缀信息。
      这些属性在data中都是可选的,同时存在一定的依赖性:scheme未指定,host就被忽略;host未指定,port就被忽略;scheme和host都未指定,path就被忽略。
      URI的匹配规则是:只要filter中声明的部分Intent中也存在,则匹配。Intent中多的部分不影响匹配。

    • data匹配规则

      • Intent当中不包含URI和MIME:filter中也没有指定URI和MIME。
      • Intent中只包含URI,没有MIME(没有直接指定,从URI中也无法判断):URI匹配filter中的URI,且filter也没有指定MIME。
      • Intent中只包含MIME,没有URI:MIME匹配filter中的MIME,且filter没有指定URI。
      • Intent中包含URI和MIME(直接指定,或从URI中判断出):MIME要匹配filter中的MIME;URI要匹配filter中的URI,或者Intent中是contentfile类型的URI同时filter没有指定URI。所以如果filter中只列出了MIME,则他会被假定支持contentfile类型的URI。
      • 如果Intent中指定了URI或者MIME,但是filter中没有data,则不匹配。
    • 在隐式启动之前,可以通过PackageManager的queryIntentActvities方法,或者Intent的resolveActivity方法查询是否有匹配的Activity存在。

    • 因为data标签可以有多个,所以同一个filter下的多个data会形成一个总的匹配规则。例如:

    <intent-filter>
        <data android:scheme="http"/>
        <data android:scheme="content"/>
        <data android:host="123"/>
        <data android:mimeType="image/*"/>
    </intent-filter>
    
    则Intent需要执行setDataAndType(Uri.parse("http://123"), "image/*"))或者setDataAndType(Uri.parse("content://123"), "image/*"))才能匹配。

总结:

  • action和category:Intent中有的只要IntentFilter中也有,就匹配。filter中定义了一些操作集,Intent则定义了一个操作。
  • data:Intent中指定的data和type,在IntentFilter存在一个完全匹配,就匹配。其中,MIME type需要相等才匹配;URI的匹配重点在于scheme,只要filter中的范围限定大于Intent即匹配。另外scheme有潜在的默认的值:content和file,如果filter中不指定scheme,Intent中指定了这两种URI,可以匹配;Intent中不指定URI,也可以匹配。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值