关于Activity你必须掌握的知识(本篇基于8.0去分析)

本文详细探讨了Activity的启动模式及其应用场景,taskAffinity属性的影响,以及如何处理屏幕旋转时的状态保存。此外,文章还深入分析了Activity从启动到创建的整个过程,包括涉及的关键类和方法,如AMS、ActivityThread、Instrumentation等,揭示了Activity生命周期管理的底层机制。
摘要由CSDN通过智能技术生成

1. Activity启动模式以及使用场景?

  1. standard 标准模式 使用场景: 邮件,默认使用标准模式
  2. singleTop 栈顶复用 :登录页面 ,微信支付 微信回调,推送通知栏等
  3. singleTask 栈内单例模式: 主页面等重复调用的页面
  4. singleInstance 栈内单例模式 系统Launcher, 锁屏页面等,此种模式下系统会为这个模式下的Activity单独开辟一个栈
  5. 总结 singleTop ,singleTask ,singleInstance 三种模式如果应用内存在Activity的实例,就不会重新去创建Activity的实例,而是调用Activity的onNewIntent函数 从而Activity的oncreate和onstart没有被调用

2. taskAffinity属性

taskAffinity属性和Activity的启动模式息息相关, 这个属性在mainfest中设置,可以理解为taskAffinity为宿主Activity指定了存放的任务栈, taskAffinity只有和singleTask启动模式匹配使用,启动的Activity才会运行在名字和taskAffinity相同的任务栈中

3. onSaveInstanceState()和onRestoreInstanceState()

  • Activity中出现异常关闭时候,尽管实际的Activity已经销毁,但是Android系统会记住它已经存在,系统会创建一个新的实例的Activity使用一组保存的数据来描述Activity在被销毁的状态,这组数据存储在Binder对象的键值对的集合中.

  • onSaveInstanceState 保存你的Activity状态.

     @Override
        protected void onSaveInstanceState(Bundle outState) {
         
            outState.putString("Activity_State","需要保存的数据");
            // 调用父类交给系统处理,这样系统能保存视图层次结构状态
            super.onSaveInstanceState(outState);
        }
    
  • onRestoreInstanceState()

     @Override
        protected void onRestoreInstanceState(Bundle savedInstanceState) {
         
            super.onRestoreInstanceState(savedInstanceState);
          //得到异常状态下的实例保存的数据
           String state = savedInstanceState.getString("Activity_State");
            
        }
    
  • 以上二种onSaveInstanceState()和onRestoreInstanceState()触发条件只在Activity异常情况下触发,正常情况下的Activity不会执行以上二个方法,可以自行验证. 具体使用的话如当前页面接受到另外页面传递过来的数据,而且当前页面可能存在奔溃情况, 可以用到这二个方法.

4. onConfigurationChanged()属性屏幕旋转

  • 当系统的配置信息发生改变时,系统才会调用此方法,只有在配置文件AndroidMainfest中处理了configChanges属性,对应的设备配置,该方法才会被调用,

      <activity
                android:configChanges="screenSize|orientation"
                android:name=".MainActivity"
                android:label="@string/app_name">
    
  • 当屏幕方向发生改变时,Activity会被销毁重建,如果在AndroidMainfest中添加处理屏幕方向配置信息,则Activity不会被销毁,而是调用onConfigurationChanged 方法

  • configChanges设置取值

    img

  • 当用户接入一个外接键盘时,默认软键盘会隐藏,系统会自动使用外设键盘,这个过程中Activity的销毁和隐藏执行了二次,并且onConfigurationChanged()方法不会调用,但是在配置文件中设置android:configChanges="keyboardHidden|keyboard"。当接入外设键盘或者拔出外设键盘时,调用的周期是先调用onConfigurationChanged()周期后销毁重建

    1. 分析,为何会二次销毁重建. 一次是键盘的插入当设置android:configChanges="keyboardHidden|keyboard"之后,就不会销毁重建,而是调用onConfigurationChanged()方法。

    2. 但是还有一次销毁重建一直存在. 经过测试发现,接入了外设,除了改变键盘类型的改变,触摸屏也发生改变,

    3. 总结 如果键盘类型发生改变,configChanges属性配置如下的Activity才不会销毁重建,且回调onConfigurationChanged方法:

       <activity
                  android:configChanges="keyboard|keyboardHidden|touchscreen"
                  android:name=".MainActivity"
                  android:label="@string/app_name">
      

5. (主要)Activity 到底是如何启动的

  • 主要分为4个部分来叙述整个Activity是如何启动的
  1. 涉及的名词简介,
  2. Launcher请求AMS过程
    3.AMS到ActivityThread的调用过程,
    4.ActivityThread启动Activity的过程
1. 涉及的类名介绍:
  • ActivityManagerServices 简称AMS 服务端对象,负责整个系统中Activity的生命周期
  • ActivityThread App的入口, 当App开启后,会调用它的main()方法开始运行,main()主要就是开启一个消息循环队列,与AMS配合完成Activity的管理工作, (ActivityThread就是UI线程或者主线程).
  • ApplicationThreadProxy 是ApplicationThread在服务器端的代理对象,负责和客户端的ApplicationThread通讯,但是在android8以后, ApplicationThreadProxyIApplicationThread 取代了,IApplicationThread实际上实现的ApplicationThread
  • instrumentation 每个应用程序只有一个instrumentation 对象每个Activity内部都有一个对改对象的引用,很多时候理解为应用程序进程管家,ActivityThread要创建或者暂停某个Activity时候,都需要instrumentation对象来进行具体操作
  • ActivityStack Activity在AMS的栈管理,用来记录已经启动的Activty的先后关系,状态信息等,通过ActivityStack决定是否需要启动新的进程.
  • ActivityRecord ActivityStack的管理对象,每个Activity在AMS对应的ActivityRecord,来记录Activity的状态以及其他管理信息,其时就是服务端的Activity对象的映像,
  • TaskRecord AMS抽象出来的一个任务概念,记录ActivityRecord的栈,一个Task包含若干个ActivityRecord,AMS用TaskRecord确保Activity启动和退出的顺序,
2. Launcher请求AMS的过程
  • 此处省略init进程的创建,Zygote进程, SystemService,Launcher进程的创建.如果想了解的请自行查看资料和源码

  • Launcher是一个Activity, 它的作用就是创建一个桌面程序,存放日常App的入口,

    public final class Launcher extends Activity
            implements View.OnClickListener, OnLongClickListener, LauncherModel.Callbacks,
    View.OnTouchListener {
         
      	...	
           Object tag = v.getTag();
            if (tag instanceof ShortcutInfo) {
         
                onClickAppShortcut(v); //点击应用图标
            } else if (tag instanceof com.android.launcher3.FolderInfo) {
         
                if (v instanceof FolderIcon) {
         
                    onClickFolderIcon(v); //点击文件夹
                }
            } else if ((FeatureFlags.LAUNCHER3_ALL_APPS_PULL_UP && v instanceof PageIndicator)||(v == mAllAppsButton && mAllAppsButton != null)) {
         
                onClickAllAppsButton(v);
            } else if (tag instanceof AppInfo) {
         
                startAppShortcutOrInfoActivity(v); //启动应用程序的入口
            } else if (tag instanceof com.android.launcher3.LauncherAppWidgetInfo) {
         
                if (v instanceof com.android.launcher3.PendingAppWidgetHostView) {
         
                  //小部件
                    onClickPendingWidget((com.android.launcher3.PendingAppWidgetHostView) v);
                }
            }
        ...
           private void startAppShortcutOrInfoActivity(View v) {
         
            com.android.launcher3.ItemInfo item = (com.android.launcher3.ItemInfo) v.getTag();
            Intent intent = item.getIntent();
            if (intent == null) {
         
                throw new IllegalArgumentException("Input must have a valid intent");
            }
          //开始启动Activity了. 发现startActivitySafely()其实当我们点击桌面任意图标的时候都会触发这个方法
            boolean success = startActivitySafely(v, intent, item); //判断启动Activity是否成功
            getUserEventDispatcher().logAppLaunch(v, intent); // TODO for discovered apps b/35802115
    
            if (success && v instanceof BubbleTextView) {
         
                mWaitingForResume = (BubbleTextView) v;
                mWaitingForResume.setStayPressed(true);
            }
        }
          ...
    }
    

    我们继续跟踪startActivitySafely()方法,

    public boolean startActivitySafely(View v, Intent intent, ItemInfo item) {
         
          ...
            //根Activity会在新的任务栈中启动,标志启动一个新的activity
             intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 
            try {
         
                if (Utilities
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值