1、如何摧毁一个Activity?
- 用户进程中 有A B两个Activity。假设A在上方
- A setResult设置返回数据,调用finish开始销毁
- finishActivity-》跨进程-》system_server
- 设置Activity的finishing为true,调整Activity栈的顺序
- 保留 setResult的数据到目标的ActivityRecord的result当中
- 暂停A,并启动超时检测。-》schedullePauseActivity暂停Activity-》到app进程
- 暂停完成之后调用activityPaused
- activityPaused有到了System_server
- 将要销毁的ActivityRecord添加到Stopping队列中
- 回调B应用的onActivityREsult、onNewIntent
- 开始Resume要显示的B,scheduleREsumeActiivty-》Resume即将显示的Activity,REsume完毕
- 更新ActivityManagerService的状态-》activityREsumed-》system_server进程
- 正砸哎线程的进程处于Idle装填,或者TImeOut超时时,卡死hi销毁 Activity
- 将AMS中Activity相关的数据接口以及窗口进行清除。
- 开始销毁Activity-》scheduleDestoryActivity-》App进程
- 调用scheduleDestoryActivity暂停Activity
- 因为已经暂停过,所以直接走onStop
- 调用 onDestory
2、Activity的4大启动模式,与开发中需要注意的问题,如onNewIntent()的调用
- standard:标准启动模式
- singletop:如果task中该activity不在栈顶就创建,如果在栈顶,并且调用onNewIntent()
- singleTask:保证全系统中只有该activity,该activity之上的都出栈,并且调用onNewIntent()
- singleInstance:保证全系统中只有该activity,保证task中只有它一个activity,如果存在且只有一个就调用onNewIntent()
模式的使用方法
- 1、Manifest.xml中指定activity启动模式
- 2、代码中addFlags,这个级别高
Flags
-
- FLAG_ACTIVITY_NEW_TASK 如果当前栈中不存在这task,就新建栈,并将task添加到新栈顶。存在就将它提到栈顶
-
- FLAG_ACTIVITY_SINGLE_TOP 栈顶复用
-
- FLAG_ACTIVITY_CLEAN_TOP: 它的作用是在启动新的Activity时,清除在目标Activity之上的所有Activity,使目标Activity成为栈顶
- 4.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS:具有此标记位的Activity不会出现在历史Activity的列表中,使用场景:当某些情况下我们不希望用户通过历史列表回到Activity时,此标记位便体现了它的效果。它等同于在xml中指定Activity的属性:
使用注意点
- SingleTask模式的运用场景是,保持我们 应用开其后只有一个Activity的实例,比如引用的主页,用户在其它页面跳转到主页,用SingleTask就不会频繁返回。
- SingleTop模式的运用场景
- 推送相关,无论打开多少次还是只出现一个页面,符合直觉
- 商品详情里的商品详情页转跳,是singletop复用,我试了。携带参数改变就好。
- SingleInstance :拨号页面
3、Intent的隐式跳转与显示跳转,如何使用?
- 显式意图:明确了启动组件 的名称,通过完成名称来启动。
- 隐式意图:没有明确的目标组件,通过action\category\data来请求指定的服务或者操作
- 如果 一个 activity可以被隐式启动,需要再清单文件的activity节点中设置 intent-filter子节点
应用场景
- 显示启动同一应用的Activity
- 隐式可以启动同一或者不同应用的activity。
- 如果系统中存在多个Activity的intent-filter同时与你 的intent匹配,会弹对话框,列出来让你选
使用
- 显示意图
- new Intent(this,目标activity.class)
- intent.setClass(this,目标activity.class)
- intent.setClass 包名
- setComponent
- 隐示意图
- category
- action
- data
- 当然 被调用者要再清单文件里写好
4、Activity A跳转B,B跳转C,A不能直接跳转到C,A如何传递消息给C?
- livedataBus
- EventBus
- Android组件 比如广播
- 全局变量、Application
- 静态变量
- 本地存储
- Android系统剪切板
5、Activity如何保存状态的
有以下几种状态让Activity状态发生改变
- 配置变更,如屏幕旋转
- 系统自动销毁Activity(当系统内存不足时)
- 手动销毁Activty(点击返回)
方法
- ViewModel将数据保存再内存中并于一个Activity相关联,配置更改期间依旧保存在内存中。系统会自动将ViewModel与发生配置更改后的新Activity关联
- 如果时Activity被杀,而不是 App。则可以用ViewModel。单纯系统内存不足会调用onLowMemory,可以在里边持久化。对于一些重要的信息,我一般都是修改保存的。
- onSaveInstanceState()回调在正常终止应用时被调用,这个瞬间可保存数据,等到下一次打开该Activity的时候 ,onRestoreInstanceState()中取数据就好了。
描述以下Activity的启动流程,从给点击图标开始
- 用户点击桌面图标其实时点击launcher。launcher通过SystemService获取System_server中的SystemManager代理。
- 通过代理获取AMS代理(10之后时获取AMS代理之后再获取ATMS),ATMS检测这个应用对应的进程是否存在
- 存在就用热启动恢复Activity
- 不存在就冷启动,通过socket和Zygote通信。请求它fork App进程。
- App进程被fork之后,通过反射调用ActivityThread中的main函数
- Looper.prepare()
- new ActivityThread().attach()
- Looper.loop不停接收信息
- 我们回到attach()
- ATMS调用attachApplication
- ATMS通过 AMS与ApplicationThread通信
- ApplicationThread的 bindApplication开始执行,初始化应用,加载资源和设置
- application 生命周期完成,完成初始化和设置
- Activity启动
- scheduleLauchActivity
- ActivityThread通过反射调用Activity的attach方法,将Activity和ApplicationThread管理来奶起来
- 调用onCreate
7、Service的生命周期是什么样的?
- startService-》onCreate-》onstartCommand()->running-》onDestory。
- 调用者如果没有调用stopService的话,就会一直存在
- 第一次startService调用第一次是走onCreate onstartCommand
- 如果第二次startService时,上一个Service还没结束,那么只执行onstartCommand。不会新建
- bindService-》onCreate-》onBind-》running-》onUnbind-》onDestory
- 和调用者共存亡。当然也已调用unbindSerivice来停止服务
- 第一次bindService的时候走onCreate onBind 如果没结束 那么第二次bindService的时候走onBind
- 交叉调用的话,第二次调用的就是对应流程的第二个 。
8、什么情况下会使用Service
- 当需要在后台运行的程序时,使用service。我以前做手指指纹时,会有个系统服务,开机自启,为指纹比对 提供服务。
项目开发中给,如何拥有service的进程具有较高的优先级
Android 系统尽量保持拥有 service的进程运行,只要这个service已经被启动或者bind了 。当内存不足时,拥有service的今晨更具有 较高的优先级
- startForeground将Service设置为前台服务。
- 使用bindService,绑定到Activity
- 为Service定义正确的优先升级
9、Service和Thread
- 他们没点关系,Thread开启一个子线程,在里面做一些耗时操作不会阻塞主线程的运行。Service其实时运行在主线程里,也可以执行后台任务罢了。它可以在后台执行长时间运行的操作而不提供用户界面。Service可以与其他组件(如Activity)进行通信,但它本身不与用户交互。
- 为什么要用 Service,而不用 Thread 呢?
- Thread是CPU分配的基本单位,可以用thread执行一些异步操作
- Service是android的一种机制,默认 Local Service主进程的main线程上。如果Remote Service 表示运行在独立进程的main线程上。
- service是一种消息服务,可以存在Context的地方调用它,context.startService。甚至可以在Service里注册广播,当然这些thread做不到的。
10、Intentservice和Service什么区别
IntentService有个方法onHandleIntent在子线程中调用,因为service是主线程中调用,所以呢如果用service又比较耗时,那么就可以用Intentservice
本质上IntentService也是开了一个线程,但是IntentService是继承自Service的,所以根据Android系统Kill Application的机制,使用IntentService的应用的优先级更高一点。通俗点说如果使用IntentService做后台任务时,当您的程序退到后台时,被杀死的几率会更低一点。
既然IntentService是在Service里开启线程去做任务处理,那我直接在Service里启动线程去做不就好了吗?当然可以,但是IntentService已经帮您封装好了,为什么还要自己再去实现IntentService的一套逻辑呢? IntentService会在任务执行完成后自行结束自己,而不需要外部去调用stopService了。
11、ContentProvider如何定义?使用场景是什么?
- ContentProvider是Android提供的一个组件,主要用于管理和数据共享。这里的数据管理里是通过定义同意的访问接口来实现,如增删改查。
- 采用了来了URL机制,将数据以URL的形式区分,这样其它App就可以采用标准的URI规范来访问同意出数据,不用直到具体细节。比如通讯录,日历,短信。ContentProvider底层使用凉了binder来完成App进程之间的通信,同时匿名共享内存来作为共享数据的实现方法。
- 安全性:ContentProvider对每处数据URI添加了权限管理机制,以控制该数据的访问者及访问方式。
- 编写一个类继承COntentProvider
- 实现所有抽象方法。
- 定义ContentProvider的Uri
- 使用UriMatcher对象映射Uri返回代码
- 在AndroidManifest.xml文件中使用< provider>标签注册ContentProvider:
12、BroadcaseReciver的静态注册和动态注册的区别
动态注册和静态注册
- 动态注册 就是在代码中注册 ,当然 记得要在onDestory中unregisterRegister
- 因为未被注销 的receiver持有PendingIntent,进而持有了activity
- 静态注册,写个类 进程BoradcaseREceiver,然后再清单文件中声明action
13、广播的 分类与工作 原理
- 广播分为有序广播和标准广播,采用的一个localBroadcastReceiver对广播进行管理。
- 标准广播
- 一种异步执行的 广播 ,发出后,所有的接收器会同时 收到这条广播无法被中断
- 有序广播
- 按照接收者优先级从高低传递,如果同样优先级就看谁先注册
- 先收到的接收者可以更改广播内容甚至 终止广播的传递
原理
静态广播注册原理
是PMS在系统启动的时候扫描已经安装的应用目录(应用安装时,也会去扫描该应用)-》清单文件,都存起来构建完成apk信息树,其中包括声明的receiver,先系统应用再第三方应用。。Intent去各个组件通信的时候,会调用PMS去查查找对应的组件列表,找到相关组件进行类似用于启动的操作,PackageManagerService.queryIntentReceivers去查询静态广播
动态广播注册原理
- 注册广播最终调用到activityManager.getService().registerReceiver(),这个方法马上执行到AMS
- 注册完记得unregisterReceiver,防止内存泄漏
- 发送广播是
- ActivityManagerNative.getDefault().broadcastIntent()
- ->ActivityManagerService.broadcastIntent
- ->ActivityManagerService.broadcastIntentLocked。
- 广播 接收者通过binder向AMS进行 注册
- 广播 发送者通过binder向AMS发送 广播
- AMS查询符合响应条件(IntentFilter/Permission等)的BroadcastReceiver,将它放到BroadCastreceiver相应的 消息循环队列中。
- 消息循环拿到 此广播,回调BroadcastReceiver中的onREceiver方法。当然不同广播 类型及不同的注册方式,具体实现会有不同。
- 广播发送者和广播接收者分别属于观察者模式中的消息发布和订阅端,AMS属于中间的处理中心 ,发送者和接收者的执行是异步的 ,发送者不关心接收者能不能接收,有无 接收 ,何时接收
14、什么是有序广播
- 按照接收者优先级从高低传递,如果同样优先级就看谁先注册
- 先收到的接收者可以更改广播内容甚至 终止广播的传递
15、介绍一下Android中的Context
- 常常被 翻译为上下文,可以理解未应用程序环境中全局信息的接口,整合了很多系统及的服务,可以 用来得到应用中的类、资源。以及应用程序调起操作,比如Activity、Service等,这个Context是个抽象类,不含有具体的函数实现
- Context是维持Android程序中各组件正常工作的一个核心功能类,抽象类。
- 核心实现类,ContextImpl
- 还有两个为ContextWrapper和ContextThemeWrapper。
ContextImpl
- 为Activity和其它应用程序组件 提供基本上下文对象,就是对COntext的实现。
ContextWrapper类介绍
- 是个装饰着模式 ,mBase依赖ContextImpl,让ContextWrapper拥有COntextImpl的能力。和主题无关的Applicaton和Service直接继承ContextWrapper直接继承Contextwrapper。
- 主要是为了降低耦合,多态,安全,封装,资源管理所以用装饰类。
ContextThemeWrapper
- Activity和主题相关,要用COntextTHemeWrapper再装饰一层。然后继承它 。
Context的数量
- Activity数量 + Service数量 + 1(Application只有1个)
使用注意事项
- 静态对象持有Context对象会有问题,可能内存泄漏,因为静态数生命 周期长于普通对象,当Context被销毁 时,静态对象持有Context引用,导致context无法被GC回收,导致内存泄漏。
- 长 生命周期用Application
- 不要用生命周期长于Activity的对象 持有到Activity的引用
- 精良不在Activity中国使用非静态内部类,因为会隐式持有。如果用就用静态内部类,然后外部实例弱引用。
16、Android 中有多少类型的 Context,它们有什么区别?
- Application Service 和Activity
- 共同点:
- 前两个是ContextWrapper派生的,其中ContextWrapper的成员变量 mBase可以用来存放系统实现的 COntextImpl,这样再执行Actiivty的Context方法时,就可以通过静态代理最终 执行到COntextImpl方法。我们调用ContextWrapper的getBaseContext就能得到COntextImpl的实例。
- 不同点:
- Activity显示界面,所以继承了ContextWrapper的子类ContextThemeWrapper,因为其中提供了一些主题、显示界面的能力。
- Application、Service都是直接 继承COntextWrapper。
- 和UI相关都应该用Activity作为 COntext来处理,否则会爆粗或者使用默认主题。
17、Android开发中Context有什么用?
- Context相当于应用的大管家
- 四大组件的信息交互,启动 Actiivyt、广播、服务,获取ContentResolver
- 获取系统/应用资源:包括AssetManager、PackManager、Resource、System Service以及color、String、drawable。
- 文件,包括获取缓存文件夹、删除文件、SharedPreference 相关等
- 数据库Sqlite相关
- 其它辅助功能,比如配置ComponentCalllbacks,监听配置信息改变、内存 不足等事件。
18、ContextImpl实例是什么时候生成的,Activity的 onCreate里 能拿到这个实例 吗
- Activtiy真正开始启动时从ActivityThread.performLaunchActivity开始的
- 通过classLoader加载加载目标Activity类,从而创建对象
- 从packageInfo里获取Application对象
- 调用createBaseContextForActivity方法创建ContextImpl
- 调用activity.attach(contextImpl,application)这个方法就把Activity和Application以及COntextImpl关联起来了 、
- 最后 调用activity.onCreate生命周期回调
- Activity是先创建类,再初始化Context,最后调用onCreate。 Application 、Service 里的 Context 初始化也都是这样的。
19、ContextImpl、ContextWrapper、ContextThemeWrapper有什么区别?
- ContextWrapper和ContextThemeWrapper都是ContextWrapper都是Context的代理类,COntextThemeWrapper有自己的theme和resource。Resource可以传入自己的配置。
- ContextImpl是Context的主要实现类,Activity、Service个Application的Base Context都是由它建立 ,COntextWrapper和ContextThemewrapper代理的就是 ContextImpl本身。
- ContextImpl和ContextThemeWrapper的主要区别是,ContextThemeWrapper由Configuration对象,Resource可以根据这个对象来初始化。
- Service和Application使用同一个Resource,和Activity使用的Resource不同。
20、Activity Context、Service Context、Application Context、Base Context有什么区别
- 生命周期不一样:Application Context是整个应用,Activity、SErial对应 自己的生命周期。Base Context主打一个封装数据和获取数据,是一个基础实现,其实就是ContextWrapper中的 mBase对象,也就是COntextImpl。
- 作用范围:看上边
- 能力:Application Context有许多功能并不适合用于与UI相关的任务,这些功能通常由Activity处理。BaseContext并没有直接处理UI相关任务的能力。
- 继承关系:Activity、Service和Application的Base Context都是由ContextImpl创建的,且创建的都是 ContextImpl对象,即他们都是ContextImpl的代理类。BaseContext是基于ThreadLocal实现的
- Activity Context 是ContextWrapper代理ContextImpl的。Service Context、Application Context是ContextThemeWrapper继承ContextWrapper代理ContextImpl的,所以 前者和后两位REsource不一样。
- getApplicationContext返回的就是Application对象本身,一般情况下它对应的是应用本身Application对象,但也可能是系统的某个对象
21、为什么不推荐使用baseContext
- 易用性问题:BaseContext主打一个基础封装,主要封装数据和说取数据。对于大多数于开发者而言。用AcitivtyContext或者ServiceContext更方便好用。
- 安全性问题:由于BaseContext没有像Activity Context和Service Context那样的安全机制,可能存在风险,用户修改BaseCOntext可能出现错误。
- 功能限制BaseCOntext和Activity本身对REsource以及THeme的相关行为是不同的。使用BaseContext可能初夏按无法 预期的现象。
- 生命周期问题:BaseContext的生命周期与线程相关,而不是与Activity或Service相关。生命周期不一致,使用不当。容易内存泄漏
22、ContentProvider里的Context是什么时候初始化的?
- ContentProvider不是context,其中有个成员变量mContext,通过构造函数传入的。
- 应用创建Application,Activity.handleBindApplication
- 创建Aplication
- 初始化Application 的COntext
- 执行installContentProviders并传入创建好Application来创建COntentProvider
- 执行Application.onCreate
- ContentProvider的context在Application创建之后,但是onCreate方法调用之前初始化的。
23、broadcastREceiver里的Context是哪里来的
- 动态注册,Context。registerREceiver动态注册BroadcastREceiver时,会生成一个REceiverDispatcher会持有这个Context,这样当有广播分发到它时,执行onReceiver就可以把发起者比如activity的Context传递过过来。所以不用是要unregisterREceiver取消注册,不然这个Context就泄露了。
- 静态注册:最终执行的是ActivityThread.handleReceiver.这个方法直接 通过ClassLoader去创建一个BroadCastReceiver对象,传递给onReceiver方法的Context则是通过context.getReceiverRestrictedContext生成一个 以Application为mBase的COntextWrapper。注意这边的 Context 不是 Application
24、Fragment的生命周期?
- onAttach-》onCreate-》onCreateView-》->onActivityCreated->onStart-》onResume-》onPause-》onStop-》onDestoryView->onDestory->onDetach
- setUserVisibleHint():配置Fragment可见或者不可见。
getUserVisibleHint():获得Fragment的状态是可见、不可见的,如果可见则进行懒加载操作。
25、fragment和Activity之间怎么通信?
- livedata
- Activty实现一个接口,fragment的onAttach中写个mCallback用来接收activty的赋值
26、Fragment的生命周期在开发中如何使用?
- Fragment必须放在一个Activity中,Fragment有自己的生命周期,并且收到宿主Activity生命周期的影响。
- attach 与activity交互
- onCreate 创建时调用,初始化操作,加载数据
- onCreateView 设置布局和视图,生成view对象返回
- 之后onActivityCreated Activity完成启动回调
- 之后没啥好说的和Actvivity圣米格逆周期一样。
- 在onDestory之前先销毁viewonDestoryView
27、Fragment的构造函数为啥不让传参 ?
- 因为销毁重建后用instantiate来创建fragment,只会调用无参构造构造函数,那构造函数的参数就是空的,容易出错,一般都传在bundle里传过去的
28、Fragment add和replace的区别,分别对Fragment的生命周期影响
- 同一容器只添加一个Fragment时,add和replace效果一样。
- 添加多个时
- 如果是add:FramentA 后add FragmentB。则hideA addB showB
- 优点:让老Fragment显示时快。支持 Fragment中View的显示、隐藏
- 缺点:内存中保存的数据 过多,容易OOM
- 如果是replace,FragmentA被替换是走销毁流程,传递给repllace方法的Fragment走生命周期创建流程
- 优点:节约内存,不要颗粒剂释放
- 缺点:频繁创建和 销毁 Fragment,造成额外性能开销
- 如果是add:FramentA 后add FragmentB。则hideA addB showB
- 源码:replace其实就是remove在add
29、如何判断一个App在前台还是后台
- RunningTask/RunningProcess 5.0之后只能返回自己和系统一些不敏感的task 但是够用了
- ActivityLifeCycleCallback 拿到生命周期的 回调
30、Activity、Intent、Service 是什么关系?
- Activity:负责与用户交互,处理用户输入并显示UI,当然也可以交给fragment在其上显示。Activity之间可以通过Intent进行切换,也可以通过Service在后台执行任务。
- Service:可以 在后台执行操作而不提供用户界面的应用组件。Service可以通过Intent启动Service或者Activity
- Intent:如上所属,是他们各自沟通或者相互沟通的桥梁