Android四大组件知识点笔记

2,054 阅读15分钟

「这是我参与2022首次更文挑战的第2天,活动详情查看:2022首次更文挑战」。

Android四大组件

分别为activity、service、content provider、broadcast receiver。


一、android四大组件详解

1、Activity

(1)一个Activity通常就是一个单独的屏幕(窗口),它上面可以显示一些控件也可以监听并处理用户的事件做出响应。

(2)Activity之间通过Intent进行通信。

(3)android应用中每一个Activity都必须要在AndroidManifest.xml配置文件中声明,否则系统将不识别也不执行该Activity。

2、Service

(1)service用于在后台完成用户指定的操作。service分为两种:

(a)started(启动):当应用程序组件(如activity)调用startService()方法启动服务时,服务处于started状态。

(b)bound(绑定):当应用程序组件调用bindService()方法绑定到服务时,服务处于bound状态。

(2)startService()与bindService()区别:

(a)started service(启动服务)是由其他组件调用startService()方法启动的,

这导致服务的onStartCommand()方法被调用。当服务是started状态时,

其生命周期与启动它的组件无关,并且可以在后台无限期运行,即使启动服务的组件已经被销毁。

因此,服务需要在完成任务后调用stopSelf()方法停止,或者由其他组件调用stopService()方法停止。

(b)使用bindService()方法启用服务,调用者与服务绑定在了一起,

调用者一旦退出,服务也就终止,大有“不求同时生,必须同时死”的特点。

(3)开发人员需要在应用程序配置文件中声明全部的service,使用标签。

(4)Service通常位于后台运行,它一般不需要与用户交互,因此Service组件没有图形用户界面。

Service组件需要继承Service基类。Service组件通常用于为其他组件提供后台服务或监控其他组件的运行状态。

3、Content Psrovider

(1)android平台提供了Content Provider使一个应用程序的指定数据集提供给其他应用程序。

其他应用可以通过ContentResolver类从该内容提供者中获取或存入数据。

(2)只有需要在多个应用程序间共享数据是才需要内容提供者。

例如,通讯录数据被多个应用程序使用,且必须存储在一个内容提供者中。它的好处是统一数据访问方式。

(3)ContentProvider实现数据共享。ContentProvider用于保存和获取数据,并使其对所有应用程序可见。

这是不同应用程序间共享数据的唯一方式,因为android没有提供所有应用共同访问的公共存储区。

(4)开发人员不会直接使用ContentProvider类的对象,大多数是通过ContentResolver对象实现对ContentProvider的操作。

(5)ContentProvider使用URI来唯一标识其数据集,这里的URI以content://作为前缀,表示该数据由ContentProvider来管理。

4、Broadcast Receiver

(1)你的应用可以使用它对外部事件进行过滤,只对感兴趣的外部事件(如当电话呼入时,或者数据网络可用时)

进行接收并做出响应。广播接收器没有用户界面。

然而,它们可以启动一个activity或serice来响应它们收到的信息,或者用NotificationManager来通知用户。

通知可以用很多种方式来吸引用户的注意力,例如闪动背灯、震动、播放声音等。

一般来说是在状态栏上放一个持久的图标,用户可以打开它并获取消息。

(2)广播接收者的注册有两种方法,分别是程序动态注册和AndroidManifest文件中进行静态注册。

(3)动态注册广播接收器特点是当用来注册的Activity关掉后,广播也就失效了。

静态注册无需担忧广播接收器是否被关闭,只要设备是开启状态,广播接收器也是打开着的。

也就是说哪怕app本身未启动,该app订阅的广播在触发时也会对它起作用。

二、android四大组件总结:

(1)4大组件的注册

4大基本组件都需要注册才能使用,每个Activity、service、Content Provider都需要在AndroidManifest文件中进行配置。

AndroidManifest文件中未进行声明的activity、服务以及内容提供者将不为系统所见,从而也就不可用。

而broadcast receiver广播接收者的注册分静态注册(在AndroidManifest文件中进行配置)

和通过代码动态创建并以调用Context.registerReceiver()的方式注册至系统。

需要注意的是在AndroidManifest文件中进行配置的广播接收者会随系统的启动而一直处于活跃状态,

只要接收到感兴趣的广播就会触发(即使程序未运行)。

(2)4大组件的激活

内容提供者的激活:当接收到ContentResolver发出的请求后,内容提供者被激活。

而其它三种组件activity、服务和广播接收器被一种叫做intent的异步消息所激活。

(3)4大组件的关闭

内容提供者仅在响应ContentResolver提出请求的时候激活。而一个广播接收器仅在响应广播信息的时候激活。

所以,没有必要去显式的关闭这些组件。

Activity关闭:可以通过调用它的finish()方法来关闭一个activity。

服务关闭:对于通过startService()方法启动的服务要调用Context.stopService()方法关闭服务,

使用bindService()方法启动的服务要调用Context.unbindService()方法关闭服务。

(4)android中的任务(activity栈)

(a)任务其实就是activity的栈,它由一个或多个Activity组成,

共同完成一个完整的用户体验。栈底的是启动整个任务的Activity,

栈顶的是当前运行的用户可以交互的Activity,当一个activity启动另外一个的时候,

新的activity就被压入栈,并成为当前运行的activity。而前一个activity仍保持在栈之中。

当用户按下BACK键的时候,当前activity出栈,而前一个恢复为当前运行的activity。

栈中保存的其实是对象,栈中的Activity永远不会重排,只会压入或弹出。

(b)任务中的所有activity是作为一个整体进行移动的。

整个的任务(即activity栈)可以移到前台,或退至后台。

(c)Android系统是一个多任务(Multi-Task)的操作系统,可以在用手机听音乐的同时,

也执行其他多个程序。每多执行一个应用程序,就会多耗费一些系统内存,

当同时执行的程序过多,或是关闭的程序没有正确释放掉内存,系统就会觉得越来越慢,

甚至不稳定。为了解决这个问题,Android引入了一个新的机制,即生命周期(Life Cycle)。

Activity的生命周期:

1.七大生命周期:

onCreate() 第一次创建时执行;

onStart() 显示窗口时执行;

onResume() 可获取用户焦点时执行;

onPause() 失去用户焦点时执行;

onStop() 关闭窗口时执行;

onRestart() 重新显示窗口时执行;

onDestroy() 销毁时执行;

2.各种情况下生命周期的回调规律:

(1)应用程序进来主页面后:

onCreate() 创建activity时

onStart () 启动时

onResume() 显示时

(2) 按返回退出后:

	onPause()    暂停时  -->丧失用户焦点的第一个特征
	onStop()     停止时
	onDestroy()  销毁时

(3)按home后:

onPause()    暂停时   
onStop()     停止时

(4)在home页再次点击这个应用:

onRestart()   
onStart()    启动时
onResume ()  显示时

(5)切换成横屏后:

onPause()    暂停时          
onStop()     停止时
onDestroy()  销毁时
onCreate()   创建activity时
onStart()   启动时
onResume()  显示时

注意设置 Activity 的 android:configChanges=”orientation|keyboardHidden|screenSize”时,

切屏不会重新调用各个生命周期,只会执行 onConfigurationChanged 方法

三、Activity的启动模式:

第一:什么是启动模式,启动的模式,理解成一个activity的启动的方式。

分为四种:

1、首先,我们现在没有指定任何启动模式,叫默认模式(standard)

标准的启动模式,每次激活activity时都会创建activity,创建之后,会把它放到任务栈里。

2、singleTop

如果在任务的栈顶,就重用该实例,如果栈顶不是这个activity,就重新实例化一个activity放到栈顶。

3、singleTask

如果在栈中已经有该activity的实例,就重复使用该实例,并且把压在它上边的实例全都清除掉;

如果在栈中没有找到该activity的实例,就创建一个放在栈顶。

4、singleInstance

与singletask的区别是,存放singleinstance模式的activity的回退栈,

不能有其他任何activity对象,也就是说,它自己单独有一个回退栈。

我们可以在 AndroidManifest.xml 配置的 android:launchMode 属性为以上四种之一即可

第二:两个 Activity 之间跳转时必然会执行的是哪几个方法?(重要)

一般情况下比如说有两个 activity,分别叫 A,B。当在 A 里面激活 B 组件的时候,A 会调用 onPause()方法,然后 B 调用 onCreate() ,onStart(), onResume()。这个时候 B 覆盖了窗体, A 会调用 onStop()方法. 如果 B 是个透明的,或者是对话框的样式, 就不会调用 A 的onStop()方法

第三:如何将一个 Activity 设置成窗口的样式?

只需要给我们的 Activity 配置如下属性即可。

android:theme=”@android:style/Theme.Dialog

第四:如何退出 Activity?如何安全退出已调用多个 Activity 的 Application?

1、通常情况用户退出一个 Activity 只需按返回键,我们写代码想退出 activity 直接调用 finish()方法就行。

2、记录打开的 Activity:

每打开一个 Activity,就记录下来。在需要退出时,关闭每一个 Activity 即可。

//伪代码

List lists ;// 在 application 全局的变量里面

lists = new ArrayList();

lists.add(this);

for(Activity activity: lists)

{

activity.finish();

}

lists.remove(this);

3、发送特定广播:

在需要结束应用时,发送一个特定的广播,每个 Activity 收到广播后,关闭即可。

//给某个 activity 注册接受接受广播的意图

registerReceiver(receiver, filter)

//如果过接受到的是 关闭 activity 的广播 就调用 finish()方法 把当前的 activity finish()掉

4、递归退出

在打开新的 Activity 时使用 startActivityForResult,然后自己加标志,在 onActivityResult 中处理,递归关闭。

5、其实 也可以通过 intent 的 flag 来实现 intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) 激活

一个新的 activity。此时如果该任务栈中已经有该 Activity,那么系统会把这个 Activity 上面的所有 Activity 干掉。其

实相当于给 Activity 配置的启动模式为 SingleTop。

Service的知识点

第一:Service 是否在 main thread 中执行, service 里面是否能执行耗时的操作?

默认情况,如果没有显示的指 service 所运行的进程, Service 和 activity 是

运行在当前 app 所在进程的 mainthread(UI 主线程)里面。

service 里面不能执行耗时的操作(网络请求,拷贝数据库,大文件 )

特殊情况 ,可以在清单文件配置 service 执行所在的进程 ,让 service 在另外的进程中执行。

第二:请描述一下 Service 的生命周期

Service 有绑定模式和非绑定模式,以及这两种模式的混合使用方式。不同的使用方法生命周期方法也不同。

非绑定模式:当第一次调用 startService 的时候执行的方法依次为 onCreate()、onStartCommand(), (onStart())

当 Service 关闭的时候调用 onDestory 方法。

绑定模式:第一次 bindService()的时候,执行的方法为 onCreate()、onBind()解除绑定的时候会执行

onUnbind()、onDestory()。

上面的两种生命周期是在相对单纯的模式下的情形。我们在开发的过程中还必须注意 Service 实例只会有一个,

也就是说如果当前要启动的 Service 已经存在了那么就不会再次创建该 Service 当然也不会调用 onCreate()方法。

一个 Service 可以被多个客户进行绑定,只有所有的绑定对象都执行了 onBind()方法后该 Service 才会销毁,

不过如果有一个客户执行了 onStart()方法,那么这个时候如果所有的 bind 客户都执行了 unBind()该 Service 也不会销毁。

第三:Service 的 onStartCommand 方法有几种返回值?各代表什么意思?

有四种返回值,不同值代表的意思如下:

  • (1)START_STICKY:如果 service 进程被 kill 掉,保留 service 的状态为开始状态,但不保留递送的 intent 对象。 随后 系 统 会 尝 试 重 新 创 建 service , 由 于 服 务 状 态 为 开 始 状 态 , 所以创建服务后一定会调用onStartCommand(Intent,int,int)方法。如果在此期间没有任何启动命令被传递到 service, 那么参数 Intent 将为 null。
  • (2)START_NOT_STICKY:“非粘性的”。使用这个返回值时,如果在执行完 onStartCommand 后,服务被异常 kill 掉,系统不会自动重启该服务。
  • (3)START_REDELIVER_INTENT:重传 Intent。使用这个返回值时,如果在执行完 onStartCommand 后,服务被异 常 kill 掉,系统会自动重启该服务,并将 Intent 的值传入。
  • (4)START_STICKY_COMPATIBILITY:START_STICKY 的兼容版本,但不保证服务被 kill 后一定能重启

第四:Service 的 onRebind(Intent)方法在什么情况下会执行?

如果在 onUnbind()方法返回 true 的情况下会执行,否则不执行。

BroadCastReceiver

BroadCastReceiver 是 Android 四大组件之一,主要用于接收系统或者 app 发送的广播事件。

广播分两种:有序广播和无序广播。

内部通信实现机制:通过 Android 系统的 Binder 机制实现通信。

无序广播:完全异步,逻辑上可以被任何广播接收者接收到。优点是效率较高。缺点是一个接收者不能将处理结果传递给下一个接收者,并无法终止广播 intent 的传播。

有序广播:按照被接收者的优先级顺序,在被接收者中依次传播。比如有三个广播接收者 A,B,C,优先级是 A > B > C。那这个消息先传给 A,再传给 B,最后传给 C。每个接收者有权终止广播,比如 B 终止广播,C 就无法接收到。

此外 A 接收到广播后可以对结果对象进行操作,当广播传给 B 时,B 可以从结果对象中取得 A 存入的数据。

在通过 Context.sendOrderedBroadcast(intent, receiverPermission, resultReceiver, scheduler, initialCode,

initialData, initialExtras)时我们可以指定 resultReceiver 广播接收者,这个接收者我们可以认为是最终接收者,

通常情况下如果比他优先级更高的接收者如果没有终止广播,那么他的 onReceive 会被执行两次,

第一次是正常的按照优先级顺序执行,第二次是作为最终接收者接收。如果比他优先级高的接收者终止了广播,

那么他依然能接收到广播。

在我们的项目中经常使用广播接收者接收系统通知,比如开机启动、sd 挂载、低电量、外拨电话、锁屏等。

如果我们做的是播放器,那么监听到用户锁屏后我们应该将我们的播放之暂停等。

BroadCastReceiver 的生命周期:

a. 广播接收者的生命周期非常短暂的,在接收到广播的时候创建,onReceive()方法结束之后销毁;

b. 广播接收者中不要做一些耗时的工作,否则会弹出 Application No Response 错误对话框;

c. 最好也不要在广播接收者中创建子线程做耗时的工作,因为广播接收者被销毁后进程就成为了空进程,很容易

被系统杀掉;

d. 耗时的较长的工作最好放在服务中完成;

  • 第三:什么是最终广播接收者?

最终广播是我们自己应用发送有序广播时通过 ContextWrapper.sendOrderedBroadcast()方法指定的当前应用下的广播,该广播可能会被执行两次,第一次是作为普通广播按照优先级接收广播,

第二次是作为 final receiver 必须接收一次。

  • 第四:广播的优先级对无序广播生效吗?—- 生效!!!!
  • 第五:动态注册的广播谁的优先级高?—– 谁先注册谁的优先级高!!
  • 第六:如何判断当前 BroadcastReceiver 接收到的是有序广播还是无序广播 ?

在 BroadcastReceiver 类中 onReceive()方法中,可以调用 boolean b = isOrderedBroadcast();

该方法是BroadcastReceiver 类中提供的方法,用于告诉我们当前的接收到的广播是否为有序广播

ContentProvider& 数据库

ContentProvider 是如何实现数据共享的?

在 Android 中如果想将自己应用的数据(一般多为数据库中的数据)提供给第三发应用,那么我们只能通过

ContentProvider 来实现了。

ContentProvider 是应用程序之间共享数据的接口。使用的时候首先自定义一个类继承 ContentProvider,然后

覆写 query、insert、update、delete 等方法。因为其是四大组件之一因此必须在 AndroidManifest 文件中进行注册。

为什么要用 ContentProvider?它和 sql 的实现上有什么差别?

ContentProvider 屏蔽了数据存储的细节,内部实现对用户完全透明,用户只需要关心操作数据的 uri 就可以了,

ContentProvider 可以实现不同 app 之间共享。

Sql 也有增删改查的方法,但是 sql 只能查询本应用下的数据库。而 ContentProvider 还可以去增删改查本

地文件. xml 文件的读取等。

ContentProvider、ContentResolver、ContentObserver 之间的关系

ContentProvider 内容提供者,用于对外提供数据

ContentResolver.notifyChange(uri)发出消息

ContentResolver 内容解析者,用于获取内容提供者提供的数据

ContentObserver 内容监听器,可以监听数据的改变状态

ContentResolver.registerContentObserver()监听消息。