0
点赞
收藏
分享

微信扫一扫

Android Activity总结

guanguans 2022-04-02 阅读 110

(主要参考《Android艺术探索》第一章及其它相关章节)

一、生命周期图 && 一些特殊情况

            onCreate()

            onStart()            onRestart()

            onResume()

            onPause()

            onStop()

            onDestroy()

 

可参考剪藏:Android总结篇系列:Activity生命周期 - Windstep - 博客园

                     Android activity的生命周期 - hpoi的专栏 - CSDN博客

##特殊情况与补充:

1.当Activity A跳转到透明主题的另一个Activity时,A不会调用onStop(),对应的,回来时也不会调用onRestart()和onStart()。(可以理解为透明主题Activity遮挡对当前Activity的影响,等同Toast、Dialog等的遮挡,毕竟当前Activity并没有完全不可见。)

2.点击back键回退时,生命周期流程为onPause()->onStop()->onDestroy()

3.Actvity A 跳转 Activity B时的生命周期执行流程:

    A->onPause()

    B->onCreate()

    B->onStart()

    B->onResume()

    A->onStop()

    也就是说,前一个Activity的onPause()执行完后,后一个Activity才开始执行生命周期流程,所以为了保证切换速度,onPause()中不能执行耗时的重量级操作。

4.Activity 用户主动关闭后重新打开  &&  Activity非用户主动关闭而是被系统回收后重新打开,两种情况下执行的生命周期方法相同(都是从onCreate()开始),但执行的具体过程有差别。

在后一种情况,会额外执行一些流程:

4.1关闭时:onSaveInstanceState([Bundle])->onStop()->onDestroy()

    其中onSaveInstanceState()与onPause()没有时序上的必然关系。

4.2再次开启时:onCreate([Bundle])->onStart()->onRestoreInstanceState([Bundle])

    在前面的onSaveInstanceState()中会把Activity的相关信息保存在一个Bundle对象中,并在重新打开时作为参数传递给onCreate()和onRestoreInstanceState()方法。

4.2.1 正常关闭Activity并重新打开时,onCreate([Bundle])中传入的Bundle对象是空的,非正常关闭重新打开,传入的Bundle才是非空的。正常关闭后重启Activity时,是不会触发onRestoreInstanceState()方法的。

4.3系统通过onSaveInstance()和onRestoreInstance()机制,在重新启动Activity时,会自动地做一些恢复操作操作,包括自动恢复相应的View展示与数据,具体恢复情况跟具体的View种类有关。

    因为在onSaveInstanceState()中系统默认执行的操作是,从Window开始,逐级委托下一层View来保存自己的数据。在重新创建Activity时,会逐级恢复各个View的展示。各个View具体的数据保存与恢复操作是自己做的,因此具体恢复成什么样要看View自己的特性和实现逻辑。

4.4触发系统回收分两种情况,一种是“系统配置发生变化”,另一种是内存不足。

    4.4.1“系统配置发生变化”情况触发回收时,默认情况下,系统会销毁该Activity并重新创建,自动恢复相应的View展示与数据。

    4.4.1.1 可通过配置AndroidManifest中Activity的android:configChanges属性,来设置“当系统某个配置变化时,不销毁该Activity”。常见的属性配置包括:屏幕方向、系统语言、软键盘的弹出隐藏变化 等。

    4.4.2内存不足回收Activity时会按照优先级来回收,先回收优先级低的。

优先级顺序如下:前台Activity > onPause()被遮挡的Activity(可见但非前台) > onStop()位于后台的Activity。

    另外,不含四大组件的进程也优先被系统回收。

4.5onRestart()触发时机:当Activity执行onStop()之后,但未被销毁,再次回到该Activity页面时,触发onRestart()->onStart()回调。例如点击Home键退到后台再次回到页面时,或者一个任务栈中点击back键弹出顶部的Activity,再次回到下面的Activity页面时。

    至于主动跳转到SingleTop、SiingleTask、SingleInstance模式的Activity,应该是触发onNewIntent()->onStart()。

    

二、Activity任务栈&四种启动模式

    任何Activity都被放在某一个任务栈中,这些任务栈由Android系统来管理(todo:查阅任务栈管理机制相关内容)。Android通过任务栈来管理Activity的启动关闭次序。

    默认情况下,每次点击back键,此刻的前台任务栈会弹出一个Activity,当一个任务栈为空时,就会被系统回收。

    由于不同任务间的Activity可以互相跳转,其回退弹出顺序并非弹空一个栈再弹另一个栈,具体Activity的弹出顺序由“回退列表”来决定。(todo:查阅回退列表的相关内容)

     任务栈相关:

    一般一个应用启动时,会开启一个对应的任务栈,默认与当前包名相同;但跟Activity的具体设置相关,同一个应用Activity也可以被放入多个不同的任务栈,不同应用的Activity也可以放入同一个任务栈。

    个人理解:根据桌面(启动器页面)在与其它任务栈Activity的切换过程,它表现地很像一个单例模式的Activity页面。

                     用户最初是从桌面(启动器页面)开始,点击启动某个应用,启动了其对应任务栈,然后各种启动、关闭、切换操作,实质上对应的是各种任务栈以及其中Activity的创建、销毁和切换。

                    点击Home键时,切换到桌面,当前应用页面对应的Activity进入后台,并未被销毁。

        Android 任务栈 - 简书

       (2条消息)android 任务栈的管理_哲的专栏-CSDN博客_android 栈管理机制

       Android任务栈的完全解析_qq_31860607的博客-CSDN博客_android 任务栈

##.四种启动模式的大致特性如下:

1.标准模式(Standard): 每次都重新创建一个实例,放到目标任务栈的栈顶;

2.单顶模式(SingleTop):若目标任务栈的栈顶已经是该Activity的实例A,则直接跳转到A,不再创建新的实例。跳转到A时,会触发onNewIntent()回调方法。

    即,目标任务栈的顶部只会有一个当前Activity的实例。

3.单栈模式(SingleTask):若目标任务栈中已存在该Activity的实例A,则直接跳转到A,此过程中任务栈中A上面的Activity都会出栈,最后A位于栈顶。同样,会触发A的onNewIntent()回调方法。

    即,目标任务栈中只会有一个当前Activity的实例。

4.单例模式(SingleInstance):若系统中已经存在该Activity的实例A,则直接跳转到A,触发其onNewIntent()方法;否则创建该Activity的实例B,放到一个单独的新任务栈中,并且跳转到实例B。

    即,整个系统中只会有一个当前Activity的实例,它位于一个单独的任务栈中。

##.额外补充说明:

1.Activity的目标任务栈:

一个Activity的目标任务栈默认情况与包名相同。如果要自定义,只有在SingleTask模式下自定义才有效,由属性android:taskAffinity来设置,如果设置了android:taskAffinity,则设置的值不能等于当前包名。

    todo:了解一下allowTaskReparenting属性。

    注:应用包名由AnroidManifest.xml文件中package属性来设定,例如:

        <manifest xmlns:android="http://schemas.android.com/apk/res/android"

        package="com.xxxx.xxxx"

                 ……..>

                ……….

                ……….

                </manifest>

2.通过Java代码和AndroidManfest.xml都可以设置一个Activity启动时的启动模式。若二者同时存在,则在执行中第二种方式的优先级更高。

    但注意,java代码模式无法设置SingleInstance模式,xml方式无法设置出FLAG_ACTIVITY_CLEAR_TOP标记位对等的效果。

    xml中设置方法:android:launchMode=“xxx"

    Java中设置方法:Intent.setFlags(xxx|xxx);

3.在理解上,个人的理解:

启动模式,故名思议,用什么样的方式去启动目标Activity。

这个方式既可以由Intent来说明(Java代码中设置Intent属性),也可以由目标Activity来说明(AndroidManifest.xml中)。

    最终的执行过程,与选择的启动参数有关,也与当前任务栈当前具体情况有关。

    以下为个人根据相关资料并实际运行测试后的一些相关理解:

    3.1xml静态设置的参数,与Activity绑定,表示每次都以什么方式启动;而java代码中设置Intent标记位参数只跟“本次启动操作”绑定。

         从这个方面也就可以理解:为何xml可以设置任意启动模式,而java方式无法设置SingleInstance模式,也无法完全等价地设置SingleTask模式。因为xml方式的优先级高,无论设置成任何模式,每次启动都是自洽的。 而java方式同一个Activity的不同实例启动时,所用的启动模式有可能不同,使用SingleInstance、SingleTask模式启动时可能与其它模式启动时产生冲突。

    3.2SingleTop模式只是去检测栈顶是否有相应示例,并做相应操作。

    3.3java代码中设置FLAG_ACTIVITY_NEW_TASK,作用并不等同xml中设置android:lanchMode=singleTask,实际运行的时候发现单独设置该标记位,什么特殊作用都没发生。

    当设置FLAG_ACTIVITY_CLEAR_TOP | FLAG_ACTIVITY_SINGLE_TOP时,作用才类似xml中设置singleTask。不过这种方式不能保证一个栈中只有一个目标示例,它只是在栈中找到最上面的那个实例,并把上面的其它Activity实例都弹出。

    在xml中设置android:lanchMode=singleTask, 才能保证栈中单实例,因为这样每次启动该Activity时,都是以singleTask方式启动的。

    3.4SingleInstance模式只能在xml指定,也就是说要么不设定这种模式,要么就每次都是这种模式启动。无法通过java代码来动态设置每次的启动模式。

    3.5当启动Activity时,若创建了新的A实例,则触发onCreate()->onStart()流程;若未创建新的A实例,而是SingleTop、SingleTask、SingleInstance等模式,则触发onNewIntent()->onStart()流程。 

Flag设置参考剪藏:

    Android 之Activity启动模式(二)之 Intent的Flag属性 | skywang

    Intent.addFlags() 启动Activity的20种flags全解析    

    剪藏我打赌你一定没搞明白的Activity启动模式 - Android - 掘金中对Android中这部分设计动机的讲解还不错。

4.可以用adb shell dumpsys activity activities命令,来查看一个调试中的Android手机中的当前任务栈信息。参考剪藏:adb shell dumpsys 命令用法

##Activity的标记位(Flags)

    启动Activity时,在Intent中可添加的标记位种类很多,具体可以参考上面的几个剪藏。

常用标记位:

1.FLAG_ACTIVITY_SINGLE_TOP:指定为SingleTop模式,该标记位的效果与单顶模式相同。

2.FALG_ACTIVITY_NEW_TASK:指定为SingleTask模式(很多文章都指出,实际上单独设置该flag时,并不会有什么作用)

3.FLAG_ACTIVITY_CLEAR_TOP:

    若任务栈中尚无Activity A的实例,不会有特别处理,只是放到顶部;

    若任务栈中已存在Activity A的实例,当A不位于栈顶时,弹出A所属任务栈中A之上的所有Activity,触发onNewIntent();    

            当A位于栈顶时,分两种情况:若以默认方式启动A,则弹出A,创建一个新的实例放入栈顶,所以会触发onCreate();若附加FLAG_ACTIVITY_SINGLE_TOP标记位来启动A(可理解为以单顶模式启动A),则A不弹出,触发onNewIntent()方法。

    另外,SingleTask的Activity实例,默认是带有FLAG_ACTIVITY_CLEAR_TOP标记位的。

4.FLAG_ACTIVITY_EXCLUDE_FROM_RECENT:带有该标记位的Activity,不会显示在历史记录列表中(就是点击底部菜单键弹出的那一堆选择列表)。

三、Activity的启动和关闭、信息传递

1.可通过Activity.finish()来手动关闭指定Activity。

2.启动方式有两种:

     2.1一种在各种上下文环境都可使用,可通过Context.startActivity(Intent)来启动指定Activity;

     2.2另一种在两个Activity之间可使用,并且前面的Activity可接收到后面Activity关闭时返回的信息:

          2.2.1A通过Activity.startActivityForResult(请求码,Intent)方式来启动一个Activity B;

          2.2.2Activity B执行setResult(结果码,Intent) ,然后finish()关闭自己;

          2.2.3则A在回调方法onActivityResult(请求码,结果码,Intent)中可获取对应的回调,并提取B封装在Intent中的数据。

                  注:若B未设置结果码或B运行中崩溃,则A中回调方法中结果码为#RESULT_CANCELED,值为-1。

          参考剪藏:startActivityForResult使用场景 - 简书

                            Android的startActivityForResult()与onActivityResult()与setResult()参数分析

                            onActivityResult()的用法_weixin_41008021的博客-CSDN博客_onactivityresult

四、Activity在AndroidManifest.xml中常见设置参数

常见设置参数如下:

<activity

        android:name=".module.common.activity.SampleActivity”    //名称,应为对应的包名地址

        android:screenOrientation="portrait”        //Activity的屏幕显示方向:示例为强制竖屏显示

        android:launchMode="singleTask”              //加载模式:示例为单栈模式  

        android:exported="true”                      //是否允许其它APP调起该Activity

        android:theme="@style/CommonAppTheme”        //设置主题类型,参考笔记:Android Activity界面显示相关总结

            //窗口软键盘加载模式:示例参数为:

              该Activity总是调整屏幕的大小以便留出软键盘的空间 | 用户选择activity时,软键盘总是被隐藏

        android:windowSoftInputMode="adjustResize|stateHidden”>    

            //设置捕获哪些手机状态的变化,状态变化时会触发onConfigurationChanged()回调,

                示例的设置效果为:当前尺寸|键盘显示隐藏|屏幕方向|屏幕布局设置

              默认情况下,系统状态变化时会销毁Activity再自动重新创建实例,如果不想自动销毁和重建,可以把这个状态添加到这里。

                这样当该系统状态改变时,不会销毁重建Activity,而是会触发当前Activity的onConfigurationChanged()回调方法。

        android:configChanges="screenSize|keyboardHidden|orientation|screenLayout"

        android:excludeFromRecents="true"               //是否允许显示在手机历史使用记录列表中

                                                            (就是点击手机底部导航条菜单键,弹出的那个历史应用列表) 

        android:taskAffinity=“per.sample.task”        //如果设置该参数,则会在指定的任务栈中启动。

                                                            默认不用设置,运行在包名对应的任务栈中。

        android:process="help_process"               //如果设置该参数,则会运行在指定的进程中。

                                                            默认不用设置,运行在包名对应的进程中。  

        <intent-filter>        //IntentFilter设置,详情参考笔记IntentFilter匹配规则 & Scheme调用

             <action android:name="android.intent.action.VIEW" />

             <category android:name="android.intent.category.DEFAULT" />

             <data android:scheme="abesfesee" />

        </intent-filter>

</activity>    

各参数的详细介绍参考剪藏:

        全面解析:AndroidManifest.xml文件中activity标签常用属性 - 简书    

        AndroidManifest.xml文件--Activity标签详解 - 简书

五、界面显示相关

参考笔记:Android Activity界面显示相关总结

六.Activity中常见的回调方法归纳:

##.生命周期相关:

onCreate()

onStart()

onResume()

onPause()

onStop()     

onDestroy()

onRestart()

onIntent()

##.状态信息保存与读取(用于被系统回收再次重新打开时恢复数据)

onSaveInstanceState()    //存储

onRestoreInstanceState()    //读取

onCreate(Bundle)    //直接在onCreate()中读取亦可

##.跳转与关闭

方式1:

Context.startActivity(Intent)    //跳转,Intent可以是显式的,也可以是隐式的

finish()    //关闭当前Activity

方式2:关闭时可回传数据

启动方:startActivityForResult(请求码,Intent)    //跳转

              onActivityResult(请求码,结果码,Intent)      //接收结果回调

关闭方:setResult(结果码,Intent)    //设置结果数据

              finish()        //关闭当前Activity

##.界面相关

setContentView()    //设置Activity的界面主布局

getSupportActionBar()    //获取ActionBar。需要Activity支持ActionBar,例如AppCompatActivity。

##.其它

//系统状态发生变化时的回调,具体监听哪些状态,需要监听的状态可在AndroidManifest.xml中注册Activity时设置

onConfigurationChanged(Configuration newConfig) 

onBackPressed()    //点击返回键时的回调

#.其它一些相关总结笔记和要点:

    Android Activity的四种加载模式

    Android Activity间的两种跳转方式、自我关闭方法、关闭后的结果处理

    Android横竖屏切换时,状态和信息的维护

 

(声明:部分图片获取自网络,这里只是用于学习分享,侵删!)

举报

相关推荐

0 条评论