目录

6. Android 校招复习篇三・四大组件

Android四大组件

Activity(活动)

启动模式

standard

默认启动模式,不会判断启动的 activity 在栈中是否存在,每次启动都会创建一个新的实例

singleTop

栈顶复用模式,会判断启动的 activity 是否位于栈顶。若是则直接使用栈顶实例(调用 onNewIntent()方法),若否则创建新实例位于栈顶

应用场景

适合从外界可能多次跳转到一个界面的情况。

  1. 消息推送
    • 接收通知启动的内容显示页面。例如:某个新闻客户端的新闻内容页面,如果收到10个新闻推送,每次都打开一个新闻内容页面是很烦人的(这个例子解释好像有点问题???)
  2. 登录页面
    • 登录成功跳转到主页,按下两次登录按钮,生成了两个主页。一些有启动延迟的页面(往往是动画,网络造成)也会有这样的情况。

singleTask

如果希望 activity 在整个应用程序中只存在一个实例,可以用 singleTask。

栈内单例模式,系统会判断启动的 activity 是否有实例存在栈中。如果存在则直接使用该实例,并将该 activity 之上的所有 activity 出栈;如果不存在则创建一个新的实例。

之前打开过的页面,打开之前的页面就ok,不再新建。

应用场景

适合作为程序模块逻辑入口,即程序入口点。

  1. 主页面(Home)
    • 例如浏览器的主界面,不管从多少个应用启动浏览器,只会启动一次主界面,其余情况都走onNewIntent(),并且会清空主界面上面的其他页面。
    • 假设用户在主页跳转到其他页面,运行多次操作后想返回到主页,假设不使用 singleTask 模式,在点击返回的过程中会多次看到主页,这明显就是设计不合理了。

singleInstance

堆内单例模式/单一实例模式,整个操作系统里只有一个内存实例存在。不同的应用去打开这个 activity 共享公用的同一个 activity。他会运行在自己单独、独立的任务栈里面,并且任务栈里只有他一个实例存在。

如果在启动这样的 activity 时,已经存在了一个实例,那么会把它所在的任务调度到前台,重用这个实例。

应用场景

适合需要与程序分离开的页面。

  1. 闹铃提醒,将闹铃提醒与闹铃设置分离
  2. 来电显示
  3. 呼叫来电界面
  4. 系统Launcher
注意事项

singleInstance 不要用于中间页面,如果用于中间页面,跳转会有问题(stackoverflow上有人说过)。

比如A -> B(singleInstance) -> C,完全退出后,再次启动,首先打开的还是B。

例:某个应用中用到了 google 地图,当退出该应用的时候,进入 google 地图,还是刚才的界面。

总结

LaunchMode场景
standardmainfest 中没有配置就默认标准模式
singleTop登录页面、消息推送
singleTask程序模块逻辑入口:主页面、扫一扫页面
电商中:购物界面,确认订单界面,付款界面
singleInstance闹铃提醒、来电显示、呼叫来电界面、系统Launcher

启动流程

生命周期

https://cdn.jsdelivr.net/gh/RebornQ/cdn.blog/img/reviews/Activity%20%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F.svg
Activity 生命周期

Service(服务)

Start方式开启服务

生命周期

onCreate() –> onStartCommand() –> onDestroy()

说明:如果服务已经开启,不会重复的执行onCreate(),而是会调用onStartCommand()

特点

使用步骤

  1. 定义一个类继承Service
  2. Manifest中配置该Service
  3. 使用Context.startService(Intent)方法启动该服务
  4. 不再使用时,调用stopService(Intent)方法停止该服务

Bind方式开启服务

生命周期

onCreate() –> onBind() –> onUnbind() –> onDestroy()

注意:绑定服务不回调用onStartCommand()方法。

使用步骤

  1. 定义一个类继承Service
  2. Manifest中配置该Service
  3. 使用Context.bindService(Intent, ServiceConnection, int)方法启动该服务
  4. 不再使用时,调用unbindService(ServiceConnection)停止该服务

两种启动方式的区别

  • Start方式:服务一旦开启就跟调用者没有任何关系了
  • Bind方式:调用者挂了,服务也会挂

Broadcast Receiver(广播接收器)

注册广播

在 Android 中,如果想要接收到广播信息,必须自定义我们的广播接收器(新建类继承BroadcastReceiver,并重写其onReceive()方法,实现接收到特定广播所要做的事情)。

定义好广播接收器后,要想使用它接收广播,就要注册这个广播接收器。

注册广播接收器有两种方法:静态注册和动态注册,下面会详解~

静态注册(在Manifest中)

直接在声明文件Manifest.xml<application>节点中配置广播接收器。

动态注册(在代码中)

使用Context.registerReceiver(BroadcastReceiver, IntentFilter, String, Handler)方法注册广播。

两种注册广播的方式有什么不同?

  • 静态注册:常驻型广播,不受应用生命周期影响。
    • 也就是说当应用程序关闭后,如果有信息广播来,程序依旧会被系统调用。
    • 适用场景:需要时刻监听广播。
  • 动态注册:非常驻型广播,跟随组件生命周期的变化。
    • 即组件结束 = 广播结束,在组件结束前必须移除广播接收器。
    • 适用场景:需要特定时刻监听广播。

特别注意

动态广播最好在ActivityonResume()注册、onPause()注销。

原因:

  1. 对于动态广播,有注册就必须要有注销,否则会导致内存泄漏

    重复注册、重复注销也不允许。

onResume()注册、onPause()注销是因为onPause()在 App 死亡前一定会被执行,从而保证广播在 App 死亡前一定会被注销,从而防止内存泄露。

发送广播

无序广播

所有的接收者都会接收事件,不可以被拦截,不可以被修改。

普通广播
系统广播

有序广播

按照优先级,一级一级的向下传递,接收者可以修改广播数据,也可以终止广播事件。

粘性广播

App应用内广播

常见面试题

为什么动态广播接收器在 Activity 被回收前没有手动注销会导致内存泄漏?

Content Provider(内容提供器)

Intent

常见面试题

Android 隐式和显式 Intent 的区别?(2020卓动笔试原题)

  • 显示Intent:直接指定需要打开的Activity类,意图特别明确,所以是显示的。

    设置这个类的方式可以是Class对象(如SecondActivity.class),也可以是包名+类名的字符串。

    应用内部Activity跳转常用这个方式。

  • 隐式Intent:隐式不明确指定启动哪个Activity,而是设置ActionDataCategory,让系统来筛选出合适的Activity

    筛选是根据Manifest中所有的<intent-filter>来筛选。