6. Android 校招复习篇三・四大组件
Android四大组件
Activity(活动)
启动模式
standard
默认启动模式,不会判断启动的 activity 在栈中是否存在,每次启动都会创建一个新的实例
singleTop
栈顶复用模式,会判断启动的 activity 是否位于栈顶。若是则直接使用栈顶实例(调用 onNewIntent()
方法),若否则创建新实例位于栈顶
应用场景
适合从外界可能多次跳转到一个界面的情况。
- 消息推送
- 接收通知启动的内容显示页面。例如:某个新闻客户端的新闻内容页面,如果收到10个新闻推送,每次都打开一个新闻内容页面是很烦人的(这个例子解释好像有点问题???)
- 登录页面
- 登录成功跳转到主页,按下两次登录按钮,生成了两个主页。一些有启动延迟的页面(往往是动画,网络造成)也会有这样的情况。
singleTask
如果希望 activity 在整个应用程序中只存在一个实例,可以用 singleTask。
栈内单例模式,系统会判断启动的 activity 是否有实例存在栈中。如果存在则直接使用该实例,并将该 activity 之上的所有 activity 出栈;如果不存在则创建一个新的实例。
之前打开过的页面,打开之前的页面就ok,不再新建。
应用场景
适合作为程序模块逻辑入口,即程序入口点。
- 主页面(Home)
- 例如浏览器的主界面,不管从多少个应用启动浏览器,只会启动一次主界面,其余情况都走
onNewIntent()
,并且会清空主界面上面的其他页面。 - 假设用户在主页跳转到其他页面,运行多次操作后想返回到主页,假设不使用 singleTask 模式,在点击返回的过程中会多次看到主页,这明显就是设计不合理了。
- 例如浏览器的主界面,不管从多少个应用启动浏览器,只会启动一次主界面,其余情况都走
singleInstance
堆内单例模式/单一实例模式,整个操作系统里只有一个内存实例存在。不同的应用去打开这个 activity 共享公用的同一个 activity。他会运行在自己单独、独立的任务栈里面,并且任务栈里只有他一个实例存在。
如果在启动这样的 activity 时,已经存在了一个实例,那么会把它所在的任务调度到前台,重用这个实例。
应用场景
适合需要与程序分离开的页面。
- 闹铃提醒,将闹铃提醒与闹铃设置分离
- 来电显示
- 呼叫来电界面
- 系统Launcher
注意事项
singleInstance 不要用于中间页面,如果用于中间页面,跳转会有问题(stackoverflow上有人说过)。
比如A -> B(singleInstance) -> C
,完全退出后,再次启动,首先打开的还是B。
例:某个应用中用到了 google 地图,当退出该应用的时候,进入 google 地图,还是刚才的界面。
总结
LaunchMode | 场景 |
---|---|
standard | mainfest 中没有配置就默认标准模式 |
singleTop | 登录页面、消息推送 |
singleTask | 程序模块逻辑入口:主页面、扫一扫页面 电商中:购物界面,确认订单界面,付款界面 |
singleInstance | 闹铃提醒、来电显示、呼叫来电界面、系统Launcher |
启动流程
生命周期
Service(服务)
Start方式开启服务
生命周期
onCreate()
–> onStartCommand()
–> onDestroy()
说明:如果服务已经开启,不会重复的执行
onCreate()
,而是会调用onStartCommand()
特点
使用步骤
- 定义一个类继承
Service
- 在
Manifest
中配置该Service
- 使用
Context.startService(Intent)
方法启动该服务 - 不再使用时,调用
stopService(Intent)
方法停止该服务
Bind方式开启服务
生命周期
onCreate()
–> onBind()
–> onUnbind()
–> onDestroy()
注意:绑定服务不回调用
onStartCommand()
方法。
使用步骤
- 定义一个类继承
Service
- 在
Manifest
中配置该Service
- 使用
Context.bindService(Intent, ServiceConnection, int)
方法启动该服务 - 不再使用时,调用
unbindService(ServiceConnection)
停止该服务
两种启动方式的区别
- Start方式:服务一旦开启就跟调用者没有任何关系了
- Bind方式:调用者挂了,服务也会挂
Broadcast Receiver(广播接收器)
注册广播
在 Android 中,如果想要接收到广播信息,必须自定义我们的广播接收器(新建类继承BroadcastReceiver
,并重写其onReceive()
方法,实现接收到特定广播所要做的事情)。
定义好广播接收器后,要想使用它接收广播,就要注册这个广播接收器。
注册广播接收器有两种方法:静态注册和动态注册,下面会详解~
静态注册(在Manifest中)
直接在声明文件Manifest.xml
的<application>
节点中配置广播接收器。
动态注册(在代码中)
使用Context.registerReceiver(BroadcastReceiver, IntentFilter, String, Handler)
方法注册广播。
两种注册广播的方式有什么不同?
- 静态注册:常驻型广播,不受应用生命周期影响。
- 也就是说当应用程序关闭后,如果有信息广播来,程序依旧会被系统调用。
- 适用场景:需要时刻监听广播。
- 动态注册:非常驻型广播,跟随组件生命周期的变化。
- 即组件结束 = 广播结束,在组件结束前必须移除广播接收器。
- 适用场景:需要特定时刻监听广播。
特别注意
动态广播最好在Activity
的onResume()
注册、onPause()
注销。
原因:
对于动态广播,有注册就必须要有注销,否则会导致内存泄漏。
重复注册、重复注销也不允许。
在onResume()
注册、onPause()
注销是因为onPause()
在 App 死亡前一定会被执行,从而保证广播在 App 死亡前一定会被注销,从而防止内存泄露。
发送广播
无序广播
所有的接收者都会接收事件,不可以被拦截,不可以被修改。
普通广播
系统广播
有序广播
按照优先级,一级一级的向下传递,接收者可以修改广播数据,也可以终止广播事件。
粘性广播
App应用内广播
常见面试题
为什么动态广播接收器在 Activity 被回收前没有手动注销会导致内存泄漏?
Content Provider(内容提供器)
Intent
常见面试题
Android 隐式和显式 Intent 的区别?(2020卓动笔试原题)
显示
Intent
:直接指定需要打开的Activity
类,意图特别明确,所以是显示的。设置这个类的方式可以是
Class
对象(如SecondActivity.class
),也可以是包名+类名的字符串。应用内部
Activity
跳转常用这个方式。隐式
Intent
:隐式不明确指定启动哪个Activity
,而是设置Action
、Data
、Category
,让系统来筛选出合适的Activity
。筛选是根据
Manifest
中所有的<intent-filter>
来筛选。