【读书笔记】【Android 开发艺术探索】第1章 Activity 的生命周期和启动模式

来源:互联网 发布:淘宝新锐卖家审核标准 编辑:程序博客网 时间:2024/05/16 06:14

一、Activity 的生命周期分析

            典型情况下的生命周期和异常情况下的生命周期。

           1、典型情况下的生命周期

  onCreate : 表示 Activity 正在被创建。在这个方法做一些初始化的工作;

 onRestart : 表示 Activity 正在重新启动。 一般情况下,Activity 从不可见变成可见状态时,回调用;

onStart : 表示 Activity 在被启动, 这时 Activity 已经可见,但是没有出现在前台,还无法和用户交互;

onResume : 表示 Activity 已经可见了,并且出现在前台并开始活动;

onPause : 表示 Activity 正在停止。此时可以做一些存储数据、停止动画等动作,但是不能太耗时;

onStop : 表示 Activity 即将停止,做一些稍微重量级的回收工作,同样不能太耗时;

onDestroy: 表示 Activity 即将被销毁,做一些回收工作和最终的资源释放。

备注: 

1、如果新的 Activity 采用了透明主题, 那么当前 Activity 不会调用 onStop 方法;

2、旧 Activity 先 onPause, 然后新 Activity 再启动;

3、不能在 onPause 中做重量级的操作,因为必须 onPause 执行完成后,新的 Activity 才能 onResume. onPause 和 onStop 都不能执行耗时工作,尤其是 onPause ,这也意味着我们的轻量级回收工作应该在 onStop 中操作,从而使新的 Activity 尽快显示出来并切换到前台。


二、异常时 Activity 生命周期

1、系统配置发生变化时


系统异常时会调用 onSaveInstanceState 方法,使用 Bundle 保存当前 Activity 的状态;Activity 重建后,传递异常时保存的 Bundle ,调用 onRestoreInstanceState 方法和 onCreate 方法。

        方法 onSaveInstanceState 在 onStop 方法之前调用

        方法 onRestoreInstanceState 在 onStart 方法之前调用

   

      在 onRestoreInstanceState 和 onCreate 方法中恢复数据的区别:

      onRestoresInstanceState 方法中, Bundle 不为空,官方建议在此方法中恢复数据;

      onCreate 方法中,正常情况下 Bundle 为空,在异常情况时不为空,所以,在此方法中恢复数据需要判断 Bundle 是否为空。

      

     注:系统只在 Activity 异常终止的时候才会调用 onSaveInstanceState 和 onRestanceState 来存储和恢复数据,其他情况下不会触发这个过程。但是,按 Home 和启动一个新的 Activity 会单独触发 onSaveInstanceState 的调用。

  

      2、资源不足导致优先级的 Activity 被杀死

          按优先级被杀死

             前台 Activity (正在与用户交互) > 可见但非前台 Activity (例如弹出 Dialog 的 Activity)  > 后台 Activity (已被执行 onStop 的 Activity)


     3、可通过配置 ConfigChange 使 Activity 在异常后不重建

         如果不想重建 Activity , 则在 mainfest.xml 中给 Activity 指定 configChanges 属性;在 Activity 中则会调用onConfigurationChanged 方法。

           在 mainfest.xml 中给 configChanges 指定时的常用配置:

   locale : 设备的本地位置发生了改变,一般只切换了语言;

   orientation : 屏幕方向发生了改变,这是最常用,比如旋转了手机屏幕;

   keyboardHidden : 键盘的可访问性发生了改变,比如用户调出了键盘。


二、 Activity 的启动模式

      1、Activity 的 LaunchMode

      standard 标准模式;singleTop 栈顶复用模式;singTask 栈内复用模式;singleInstance 单例模式。

        standard 标准模式:

系统默认模式,每次启动一个 Activity 都会重新创建一个新的实例,不管这个实例是否已经存在。

        使用 ApplicationContext 启动 standard 模式的 Activity 会报错。

 Intent intent = new Intent(MainActivity.this, HandlerThreadActivity.class); getApplicationContext().startActivity(intent);
      会报错: 
android.util.AndroidRuntimeException: Calling startActivity() from outside of an Activity  context requires the FLAG_ACTIVITY_NEW_TASK flag. Is this really what you want?
         解决方法: 给待启动的 Activity 指定 FlAG_ACTIVITY_NEW_TASK 标记位。

 Intent intent = new Intent(MainActivity.this, HandlerThreadActivity.class); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); getApplicationContext().startActivity(intent);


       singleTop 栈顶复用模式

        如果新 Activity 已经位于任务栈的栈顶,那该 Activity 不会被重新创建。 onCreate, onStart 方法不会调用,只会调用它的 onNewIntent 方法。 例如, ABCD , 然后 D 再启动 D , 任务栈最终变成 ABCD.

         如果是新的 Activity 已经启动, 但是不在栈顶,则会重新创建实例,并且不会调用 onNewIntent 方法。例子,ABCD, 然后 D 启动 A, 任务栈最终变成 ABCDA.

      singleTask 栈复用模式,这是一种单实例模式

   只有一个 Activity 在一个栈中存在,多次启动此 Activity 都不会重新创建实例,但是会调用 onNewIntent 方法。


               SingleInstance 单实例模式

一种加强的 SingleTask 模式, 拥有 SingleTask 模式的所有特性,并且此模式的 Activity 只能一个任务栈中。

                例子,MainActivity 、 HandlerThreadActivity 和 ThirdActivity 的 TaskAffinity 是一样的,MainActivity 启动 HandlerThreadActivity, HandlerThreadActivity 再启动 ThirdActivity , 我们使用命令行 adb shell dumpsys activity 进去可以看到,MainActivity 单独一个任务栈,HandlerThreadActivity 和 ThirdActivity 同一个任务栈

 

        TaskAffinity : the task that the activity has an attinity. Activities with the same affinity conceptually belong to the same task (to the same "application" from the user's perspective). The affinity of a task is determing by the affinity of its root activity.

默认情况下,所有 Activity 所需的任务栈的名字Wie应用的包名。 TaskAffinity 属性主要和 singleTask 启动模式或者 allowTaskReparenting 属性配对使用,在其他情况下没有意义。

在 AndroidMenifest.xml 中为 Activity 指定启动模式和 通过 Intent 中设置标志位为 Activity 指定启动模式的区别。

在Menifest.xml 中

   <activity            android:name=".ThirdActivity"            android:label="@string/title_activity_third_acvity"            android:launchMode="singleTask"            android:theme="@style/AppTheme.NoActionBar">        </activity>

   使用Intent

  Intent intent = new Intent(HandlerThreadActivity.this, ThirdActivity.class);  intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);  startActivity(intent);
      

区别:

优先级上,第二种方式高于第一种方式,如果两种同时存在,以第二种方式为准;

限定范围不同。 例如第一种方式无法直接为 Activity 设定 FLAG_ACTIVITY_CLEAR_TOP 标识,而第二种方式无法为 Activity 指定 singleInstance 模式。


       三、 Activity 的 Flags

             常用的标志位

     FLAG_ACTIVITY_NEW_TASK  对应 singleTask

     FLAG_ACTIVITY_SINGLE_TOP    对应 singleTop

     FLAG_ACTIVITY_CLEAR_TOP   具有此标记位的 Activity ,当它启动时,在同一个任务栈中所有位于它上面的 Activity 都要出栈。这个模式一般需要和 FLAG_ACTIVITY_NEW_TASK 配合使用,在这种情况下,被启动 Activity 的实例如果已经存在,那么系统就会调用它的 onNewIntent . 如果被启动的 Activity 采用 standard 模式启动,那么它连同它之上的 Activity 都要出栈,系统会创建新的 Activity 实例并存入栈顶。

     FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS

等同于在 Manifest.xml 中 android:excludeFromRecents = "true". 具有这个标记的 Activity 不会出现在历史 Activity 的列表中,当某些情况下我们不希望用户通过历史列表回到我们的 Activity 的时候,这个标记比较有效。(按  Home 键 出现)

     FLAG_ACTIVITY_NO_HISTORY

         等同于 Manifest.xml 中的 android:noHistory = "true".

         例如 MainActivity 启动 HandlerThreadActiviy ,HandlerThreadActiviy 再启动 ThirdActivity ,返回时,我们想从 ThirdActivity 跳过HandlerThreadActiviy 直接到  MainActivity ,就可以使用这个标志位。 它们各自是生命周期方法调用顺序为:




  四、IntentFilter 的匹配规则

        启动 Activity 分为显示调用和隐式调用。原则上一个 Intent 不应该既是显示调用有事隐式调用,如果二者共存的话以显示调用为主。

       隐式调用需要 Intent 能够匹配目标组件的 IntentFilter 中所设置的过滤信息,如果不匹配将无法启动相应的 Activity. IntentFilter 中过滤信息有 action 、category、 data.

       An <intent - filter>  element must contain one or more <action> elements, if it doesn't contain any, on intent object  will get through the filter. For action you define, it's best use package name as a prefin to ensure uniqueness, 例子:com.exemple.project.TRANSMOGRIFY.


      匹配规则:

1、action 的匹配规则

        与 Intent 字符串值完全一样,才能成功,区分大小写。 action 的匹配要求 Intent 中的 action 存在且必须和过滤规则中的其中一个 action 相同。

2、category 的匹配规则

         必须匹配每一个 category, 并且必须包含 "android.intent.category.DEFULT"。在Intent 中使用Intent.addCategory() 添加。

3、data 的匹配规则

         data 的匹配规则和 action 类似, 它也要求 Intent 中必须含有 data 数据,并且 data 数据能完全匹配过滤规则中某一个 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 由 mimeType 和 URI 两部分组成。

               mimeType 指媒体类型,例如 image/jpeg、audio/mpeg4-generic 和 video/* 等

               URI 的结构 

<span style="white-space:pre"></span><span style="white-space:pre"></span><scheme>://<host>:<port>/[<path>|<pathPrefix>|<pathPattern>]
                     URI 的例子

                http://www.baidu.com:80/search/info

               sheme: URI 的模式,例如 http、 file、conten t等,if a scheme is not specified for the intent filter, all the other URI attributes are igored.

               Host: URI 的主机名,例子中 www.baidu.com, if a host is not specified for the filter, the port attribute and all the path attribute are ignored.

               Port: URI 的端口,例子中的 80, 仅当 URI 中指定了 scheme 和 host 参数的时候 port 参数才有意义。

               Path 、pathPrefix, pathPattern : 这三个参数表示路径的信息。


               intent 中使用 data, 调用 setDataAndType 方法。

                intent.setDataAndType(Uri.parse("file://abc"), "image/png");

               以下两种写法等价             

            <intent-filter>                <data android:scheme="file" android:host="www.baidu.com"/>            </intent-filter>            <!--等价-->            <intent-filter>                <data android:scheme="file"/>                <data android:host="ww.baidu.com"/>            </intent-filter>

               隐式启动判断启动的结果

 //  单个匹配,最佳的结果  if (intent.resolveActivity(getPackageManager()) != null) //  返回所有成功匹配的结果 List<ResolveInfo> queryIntentActivities = getPackageManager().queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);



  




                  




0 0
原创粉丝点击