Android知识点整理

App启动流程和启动模式

启动流程

当用户点击一个App图标时,Click事件会通过Binder IPC机制调用startActivity(Intent), 最终调用到ActivityManagerService。在ActivityManagerService中做三件事:
1、通过PackageManager的resolveIntent()收集这个intent对象的指向信息,指向信息被存储在一个intent对象中。
2、通过grantUriPermissionLocked()方法来验证用户是否有足够的权限去调用该intent对象指向的Activity。
3、如果有权限, ActivityManagerService会检查这个进程的ProcessRecord是否存在。如果不存在, ActivityManagerService会创建新的进程来实例化目标activity。

ActivityManagerService创建新的进程并实例化目标activity分为三个步骤。
第一步,创建进程
ActivityManagerService调用startProcessLocked()方法来创建新的进程,该方法会通过socket通道传递参数给“Zygote”进程。 Zygote孵化自身,并调用ZygoteInit.main()方法来实例化ActivityThread对象并最终返回新进程的pid。随后ActivityThread依次调用Looper.prepareLoop()和Looper.loop()来开启消息循环。
第二步,绑定Application
第二步要做的就是将进程和指定的Application绑定起来。这个是通过ActivityThread对象中调用bindApplication()方法完成的。该方法发送一个BIND_APPLICATION的消息到消息队列中,最终通过handleBindApplication()方法处理该消息。然后调用makeApplication()方法来加载App的classes到内存中。
第三步,启动Activity
经过前两个步骤之后,系统中已经拥有了该App的进程。后面的步骤就是从一个已经存在的进程中启动一个新进程的activity了。该步骤实际调用方法是realStartActivity(),它会调用application线程对象中的sheduleLaunchActivity()发送一个LAUNCH_ACTIVITY消息到消息队列中,通过 handleLaunchActivity()来处理该消息。
经过这三个步骤,就成功启动了一个App。

启动模式

由上述App启动流程可以看出,App启动需要判断系统中是否有该App的进程,没有的话就需要创建。故App的启动模式可以根据系统中是否存在App的进程分为热启动和冷启动两种,如下:
冷启动:App没有启动过或App进程被killed, 系统中不存在该App进程。
热启动:App进程处于后台, 系统将其从后台带到前台, 展示给用户。

Activity启动模式

任务栈
1、程序打开时就创建了一个任务栈, 用于存储当前程序的activity,所有的activity属于一个任务栈。
2、一个任务栈包含了一个activity的集合, 去有序的选择哪一个activity和用户进行交互:只有在任务栈栈顶的activity才可以跟用户进行交互。
3、任务栈可以移动到后台, 并且保留了每一个activity的状态. 并且有序的给用户列出它们的任务, 而且还不丢失它们状态信息。
4、退出应用程序时:当把所有的任务栈中所有的activity清除出栈时,任务栈会被销毁,程序退出。

任务栈的缺点
1、每开启一次页面都会在任务栈中添加一个Activity,而只有任务栈中的Activity全部清除出栈时,任务栈被销毁,程序才会退出,这样就造成了用,户体验差, 需要点击多次返回才可以把程序退出了。
2、每开启一次页面都会在任务栈中添加一个Activity还会造成数据冗余, 重复数据太多, 会导致内存溢出的问题(OOM)。
为了解决任务栈的缺点,我们引入了启动模式。

启动模式(launchMode)在多个Activity跳转的过程中扮演着重要的角色,它可以决定是否生成新的Activity实例,是否重用已存在的Activity实例,是否和其他Activity实例公用一个task里。这里简单介绍一下task的概念,task是一个具有栈结构的对象,一个task可以管理多个Activity,启动一个应用,也就创建一个与之对应的task。

启动模式有如下4种:

  • standard
    standard模式是默认的启动模式,不用配置android:launchMode属性即可,当然也可以指定值为standard。跳转时不管栈中有没有已存在的实例,都生成新的实例。
  • singleTop
    配置属性android:launchMode=”singleTop”。跳转时系统会先在栈中寻找是否有对应activity实例正位于栈顶,如果有则不再生成新的,而是直接使用,否则生成新的实例。
  • singleTask
    配置属性android:launchMode=”singleTask”。跳转时如果系统发现栈中有对应的Activity实例,则使此Activity实例之上的其他Activity实例统统出栈,使此Activity实例成为栈顶对象,显示到幕前,否则生成新的实例。
  • singleInstance
    配置属性android:launchMode=”singleInstance”。跳转时会启用一个新的栈,并将Activity放置于这个新的栈结构中,并保证不再有其他Activity实例进入。
    应用场景
    singleTop:适合接收通知启动的内容显示页面。例如新闻客户端的新闻内容页面、推送消息处理页面。
    singleTask:适合作为程序入口点。例如浏览器的主界面,电商App主页面。
    singleInstance:适合需要与程序分离开的页面。例如闹铃提醒,电商App秒杀提醒。singleInstance不要用于中间页面,如果用于中间页面,跳转会有问题,比如:A -> B (singleInstance) -> C,完全退出后,再次启动,首先打开的是B。

Activity生命周期

常规生命周期

onCreate : 该方法是在Activity被创建时回调,它是生命周期第一个调用的方法,我们在创建Activity时一般都需要重写该方法,然后在该方法中做一些初始化的操作,如通过setContentView设置界面布局的资源,初始化所需要的组件信息等。 此方法中不应该做一些耗时的操作,否则可能会引起黑屏和ANR。
onStart : 此方法被回调时表示Activity正在启动,此时Activity已处于可见状态,只是还没有在前台显示,因此无法与用户进行交互。可以简单理解为Activity已显示而我们无法看见罢了。
onResume : 当此方法回调时,则说明Activity已在前台可见,可与用户交互了(处于前面所说的Active/Running形态),onResume方法与onStart的相同点是两者都表示Activity可见,只不过onStart回调时Activity还是后台无法与用户交互,而onResume则已显示在前台,可与用户交互。当Activity停止后(onPause方法和onStop方法被调用),重新回到前台时也会调用onResume方法,因此我们也可以在onResume方法中初始化一些资源,比如重新初始化在onPause或者onStop方法中释放的资源。
onPause : 此方法被回调时则表示Activity正在停止(Paused形态),一般情况下onStop方法会紧接着被回调。有一种情况是onPause方法执行后直接执行了onResume方法,这属于比较极端的现象了,这可能是用户操作使当前Activity退居后台后又迅速地再回到到当前的Activity,此时onResume方法就会被回调。当然,在onPause方法中我们可以做一些数据存储或者动画停止或者资源回收的操作,但是不能太耗时,因为这可能会影响到新的Activity的显示——onPause方法执行完成后,新Activity的onResume方法才会被执行。
onStop: 一般在onPause方法执行完成直接执行,表示Activity即将停止或者完全被覆盖(Stopped形态),此时Activity不可见,仅在后台运行。同样地,在onStop方法可以做一些资源释放的操作(不能太耗时)。
onRestart :表示Activity正在重新启动,当Activity由不可见变为可见状态时,该方法被回调。这种情况一般是用户打开了一个新的Activity时,当前的Activity就会被暂停(onPause和onStop被执行了),接着又回到当前Activity页面时,onRestart方法就会被回调。
onDestroy :此时Activity正在被销毁,也是生命周期最后一个执行的方法,一般我们可以在此方法中做一些回收工作和最终的资源释放。

异常生命周期

  • 1、相关的系统配置发生改变导致Activity被杀死并重新创建(一般指横竖屏切换)
    正常启动Activity时,onCreate,onStart,onResume方法都会依次被回调,而如果我们此时把竖屏的Activity人为的调整为横屏,我们可以发现onPause,onSaveInstanceState,onStop,onDestroy,onCreate,onStart,onRestoreInstanceState,onResume依次被调用,单从调用的方法我们就可以知道,Activity先被销毁后再重新创建
  • 2、内存不足导致低优先级的Activity被杀死
    基本类似上一种情况

当我们不想Activity在屏幕旋转后导致销毁重建时,可以设置configChange=“orientation”;当SDK版本大于13时,我们还需额外添加一个“screenSize”的值,对于这两个值含义如下:
orientation:屏幕方向发生变化,配置该参数可以解决横竖屏切换时,Activity重建问题(API<13)
screenSize:当设备旋转时,屏幕尺寸发生变化,API>13后必须配置该参数才可以保证横竖切换不会导致Activity重建。
设置了这两个参数后,当横竖屏切换时,Activity不会再重建并且也不会调用之前相关的方法,取而代之的是回调onConfigurationChanged方法。

Activity与Window/View的关系

  • Window 是什么?
    Window 是 Android 中窗口的宏观定义,主要是管理 View 的创建,以及与 ViewRootImpl 的交互,将 Activity 与 View 解耦。
  • Activity 与 PhoneWindow 与 DecorView 之间什么关系?
    一个 Activity 对应一个 Window 也就是 PhoneWindow,一个 PhoneWindow 持有一个 DecorView 的实例,DecorView 本身是一个 FrameLayout。

Activity的主要作用是生命周期的管理,Window是一个视图容器,WindowManager统一管理View。所以Activity和Window的关联主要是体现在生命周期的管理和事件的回调上,Window和View的关联体现在对View视图的处理上。

Activity与Fragment

  • 生命周期不同
    Activity有7个生命周期:onCreate()、onStart()、onRestart()、onResume()、onPause() 、onStop() 、onDestroy();
    Fragment有11个生命周期:onAttach() 、onCreate() 、onCreateView() 、onActivityCreate()、onStart()、onResume() 、onPause() 、onStop() 、onDestroyView()、onDestroy()、onDetach();
    onAttach()
    作用:fragment已经关联到activity,这个时候 activity已经传进来了, 获得activity的传递的值 就可以进行 与activity的通信里, 当然也可以使用getActivity(),前提是这个fragment已经和宿主的activity关联,并且没有脱离,有且只有调用一次。
    onCreate()
    系统创建fragment的时候回调,在里面实例化一些变量,这些个变量主要是:当暂停、停止的时候想保持的数据、只调用一次。
    onCreateView()
    第一次使用的时候 fragment会在这上面画一个layout出来, 为了可以画控件 要返回一个 布局的view,也可以返回null就什么都没有显示。
    当系统用到fragment的时候 fragment就要返回他的view,越快越好 ,所以尽量在这里不要做耗时操作,比如从数据库加载大量数据
    onActivityCreated()
    当Activity中的onCreate方法执行完后调用。当执行onActivityCreated()的时候 activity的onCreate才刚完成。所以在onActivityCreated()调用之前activity的onCreate可能还没有完成,所以不能再onCreateView()中进行与activity有交互的UI操作,UI交互操作可以在onActivityCreated()里面进行。所以呢,这个方法主要是初始化那些你需要你的父Activity或者Fragment的UI已经被完整初始化才能初始化的元素。
    onStart()
    和activity一致,启动Fragement 启动时回调,,此时Fragement可见。
    onResume()
    和activity一致 在activity中运行是可见的。激活, Fragement 进入前台, 可获取焦点时激活。
    onPause()
    和activity一致 其他的activity获得焦点,这个仍然可见第一次调用的时候,指的是 用户 离开这个fragment(并不是被销毁)
    通常用于 用户的提交(可能用户离开后不会回来了)
    onStop()
    和activity一致, fragment不可见的, 可能情况:activity被stopped了或者 fragment被移除但被,加入到回退栈中,一个stopped的fragment仍然是活着的如果长时间不用也会被移除。
    onDestroyView()
    Fragment中的布局被移除时调用。表示fragemnt销毁相关联的UI布局, 清除所有跟视图相关的资源。然后这个知识移除视图 并没有销毁而且还没有脱离activity
    onDestroy()
    销毁fragment对象, 跟activity类似了。
    onDetach()
    Fragment和Activity解除关联的时候调用。 脱离activity。
    所以Fragment比较与Activity来说会更加灵活,因为生命周期多了,可以控制的地方也就多了。
  • 使用的灵活性不同
    Fragment显得更加灵活。可以直接在XML文件中添加<fragment/>,Activity则不能;Fragment可以在一个界面上灵活的替换一部分页面,Activity不可以,Activity 只能进行跳转切换。
  • 控件加载的方式不同
    Fragment的载入是通过OnCreateView的时候通过inflater.inflate()加载布局
    Activity的载入是通过OnCreate的时候通过setContentView()加载布局

Fragment 懒加载

为什么需要懒加载?
减少不必要的资源浪费
什么情况下需要懒加载?
使用viewpager+adapter作为应用大的布局时
懒加载的实现方式:
1、setUserVisibleHint + onHiddenChanged
2、FragmentTransaction.setMaxLifecycle()

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,204评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,091评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,548评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,657评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,689评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,554评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,302评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,216评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,661评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,851评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,977评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,697评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,306评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,898评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,019评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,138评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,927评论 2 355