安卓四大组件
安卓四大组件
Activity
活动:提供一个界面让用户点击和各种滑动操作。
生命周期
- 启动活动:onCreate() -> onStart() -> onResume(),活动进入运行状态。
- 退居后台:onPause() -> onStop(),当前活动转到新的活动界面或按Home键返回主屏,进入停滞状态。
- 返回前台:onRestart() -> onStart() -> onResume(),再次回到运行状态。
- 活动退居后台且系统内存不足,系统会杀死之,若再次回到此活动,则onCreate() -> onStart() -> onResume().
- 锁定与解锁屏幕,只会调用onPause(),而不會調用onStop(),解锁後則調用onResume().
两个活动间跳转
活动A启动活动B,回调如下:
活动A的onPause() ->
活动B的onCreate() -> onStart() -> onResume() ->
活动A的onStop()
若活动B是透明主题或者是DialogActivity,则不会回调活动A的unStop().
将Activity设置成窗口模式,在AndroidMainfest.xml中配置如下:
android:theme="@android:style/Theme.Dialog"
onSaveInstanceState
活动的onSaveInstanceState()和onRestoreInstanceState()并不是生命周期方法,不同于onCreate()和onPause()等生命週期方法,其并不一定会被触发。
onSaveInstanceState()的调用条件:当应用遇到意外情况而由系统销毁一个活动时,其此方法被调用;而用户主动销毁活动时,不会调用此方法;此方法只适合保存临时性状态,而onPause()适合数据持久化保存。
应用场景:
- 屏幕方向切换
- 用户按下Home键
- 长按Home键,运行其他程序时
- 启动一个新的活动时
- 锁屏时
启动模式
- standard: 系统在启动它的task中创建活动的新实例。
默认模式,无需写配置,可以有多个相同的实例,也允许多个相同的活动叠加。 - singleTop: 可以有多个相同的实例,但不允许多个相同的活动叠加。
已有此活动在task栈顶,则不创建新实例而调用其onNewIntent(). - singleTask:
在同一应用中启动此活动,若其不存在则在当前task中创建一个新实例,否则把task中在其之上的其他活动销毁并调用此活动的onNewIntent().
在其他应用中启动此活动,会新建一个task以启动此活动。
singleTask活动允许其他活动与之在同一个task共存。 - singleInstance: 实例独立运行在task中,不允许其task有其他活动.
task
一个应用中有多个活动,这些活动以栈的形式管理。
task是指按各自打开顺序排列在栈中的一系列活动。
启动过程
- 点击桌面App图标,Launcher进程采用Binder IPC向system_server进程发起startActivity请求。
- system_server进程接收到请求后,向zygote进程发送创建进程的请求。
- Zygote进程fork出App进程,并执行ActivityThread的main方法,初始化MainLooper,主线程Handler,同时初始化ApplicationThread用于和AMS通信交互。
- App进程,通过Binder IPC向sytem_server进程发起attachApplication请求。
- system_server进程在收到请求后,进行一系列准备工作后,再通过binder IPC向App进程发送handleBindApplication请求(初始化Application并调用onCreate方法)和scheduleLaunchActivity请求(创建启动Activity).
- App进程的binder线程(ApplicationThread)在收到请求后,通过handler向主线程发送BIND_APPLICATION和LAUNCH_ACTIVITY消息。
- 主线程在收到Message后,通过反射机制创建目标Activity,并回调Activity.onCreate()等方法。
- 至此,APP正式启动,开始进入Activity生命周期,执行完onCreate/onStart/onResume方法,UI渲染后显示APP主界面。
名词解释
- Instrumentation: 是Android系统里面的一套控制方法或者钩子。
- ActivityManagerService(AMS): AMS是系统的引导服务,应用进程的启动、切换和调度,四大组件的启动和管理都需要AMS的支持。
- ActivityStarter: 是加载Activity的控制类。
- ActivityStackSupervisor: AMS通过操作ActivityStackSupervisor来管理Activity.
- ActivityStack: 用来管理系统所有Activity的各种状态。它由ActivityStackSupervisor进行管理。
- ApplicationThread: 是ActivityThread的私有内部类,也是一个Binder对象。
- Zygote: 主要功能是执行Android应用程序。其运行时会初始化并启动Dalvik虚拟机。
Context和Application
- Activity和Application都是Context的子类。
- Context描述了应用程序环境的信息,即上下文。
- Context是抽象类,Android提供了其具体实现类(ContextImpl).
- 通过Context,可以获取应用程序的资源和类,可以进行一些应用级别操作,例如:启动活动、发送广播、接受Intent和信息等。
Service
服务:可以在后台长时间运行而没有用户界面的应用组件。
- Service务分为两种工作状态,启动状态主要用于执行后台计算,绑定状态主要用于和其他组件的交互。
- 同一应用默认情况下,Service和Activity是在同一线程(主线程UI Thread)中的。
启动过程
备注: Android 技术笔记
startService
注:一般来说,同一进程内的线程间通信采用的是Handler消息队列机制,不同进程间的通信采用的是binder机制,另外与Zygote进程通信采用的Socket.
- Process A进程采用Binder IPC向system_server进程发起startService请求。
- system_server进程接收到请求后,向zygote进程发送创建进程的请求。
- zygote进程fork出新的子进程Remote Service进程。
- Remote Service进程,通过Binder IPC向sytem_server进程发起attachApplication请求。
- system_server进程在收到请求后,进行一系列准备工作后,再通过binder IPC向remote Service进程发送scheduleCreateService请求。
- Remote Service进程的binder线程在收到请求后,通过handler向主线程发送CREATE_SERVICE消息。
- 主线程在收到Message后,通过反射机制创建目标Service,并回调Service.onCreate()方法。
- 至此,服务正式启动完成。当创建的是本地服务或者服务所属进程已创建时,则无需经过上述2、3步骤。
bindService
说明:
- 图中蓝色代表的是Client进程(发起端),红色代表的是system_server进程,黄色代表的是target进程(service所在进程)。
- Client进程:通过getServiceDispatcher获取Client进程的匿名Binder服务端(即LoadedApk.ServiceDispatcher.InnerConnection),再通过bindService调用到system_server进程。
- system_server进程:依次通过scheduleCreateService和scheduleBindService方法,远程调用到target进程。
- target进程:依次执行onCreate()和onBind()方法,将onBind()方法的返回值IBinder(作为target进程的binder服务端)通过publishService传递到system_server进程。
- system_server进程:利用IServiceConnection代理对象向Client进程发起connected()调用,并把target进程的onBind返回Binder对象的代理端传递到Client进程。
- Client进程:回调到onServiceConnection()方法,该方法的第二个参数便是target进程的binder代理端。到此便成功地拿到了target进程的代理,可以畅通无阻地进行交互。
startService生命周期
仅仅开启一个后台服务,可以使用startService方法。
如果要获取Service中提供的代理对象,那么必须通过bindService方法。
手动调用startService()启动服务 -> [开始] onCreate() -> onStartCommand() -> 手动调用stopService()停止服务 -> onDestory() -> [结束].
如果服务已开启,不会重复执行onCreate(),一旦服务开启就与调用者无关,且开启者不能调用服务里面的方法。
bindService生命周期
手动调用bindService()绑定服务 -> [开始] -> onCreate() -> onBind() -> 手动调用unBindService()解锁服务 -> onUnbind() -> onDestory() -> [结束].
绑定服务不会调用onStart()或者onStartCommand(),其调用者和服务绑定(调用者挂了服务也挂),调用者可以调用服务方法。
startService和bindService同时使用
手动调用startService() -> [开始] -> onCreate() -> onStartCommand() -> 手动调用bindService() -> onBind() -> 手动调用unBindService() -> onUnbind() -> 手动调用stopService() -> onDestory() -> [结束].
onStartCommand的返回值
- START_STICKY: 粘性的
若此服务在启动时被终止,则保持在启动状态而不会保留Intent,稍后将重建服务并调用onStartCommand(),如果没有任何启动命令被传递到此服务,那么将以空的Intent调用之。 - START_NOT_STICKY: 非粘性的
若此服务在启动时被终止,并且没有启动新的Intent传递之,则此服务脱落启动状态,并且不会自动重新创建。 - START_REDELIVER_INTENT: 重传Intent
若此服务在启动时被终止,则将计划重新启动并将最后的Intent再次通过调用onStartCommand()传递。 - START_STICKY_COMPATIBILITY:
START_STICKY的兼容版本,不保证服务被终止后一定能重启。
Activity与Service通信
- 法一:添加一个继承Binder的内部类和其逻辑方法,重写Service的onBind方法以返回此内部类,再重写onServiceConnected和onServiceDisconnected以绑定服务。
- 法二:通过接口Iservice调用Service方法。
前台服务
要启用前台服务,需在AndroidMainfest.xml中配置如下:
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
前台服务的系统优先级更高而不易被回收,且前台服务有一个正在运行的图标在系统状态栏显示。
[如何正确的使用Service?](https://github.com/jeanboydev/Android-ReadTheFuckingSourceCode/blob/master/article/android/basic/03_service.md 包含前台服务的使用)
IntentService
IntentService是Service的子类,是一个异步的、会自动停止的服务。
- 特点:会创建独立的worker线程处理所有的Intent请求,处理完成后,IntentService会自动停止。
- 绑定操作:其为Service的onBind()提供默认实现(返回null),为onStartCommand()提供默认实现(将请求Intent加入队列)。
- 线程方面:其不会阻塞UI线程,而普通Service会导致ANR异常;其若未执行完上一次任务,将等待至完成后再执行新的任务。
Broadcast Receiver
广播用于进程/线程通信,无需关心接收方对数据如何。
广播分类
- 按发送方式:
- 标准广播:完全异步执行。
- 有序广播:同步执行,有先后顺序,同一时刻仅有一个接收器可接收之,优先级高者可以先收到,并且收到此广播的接收器可以截断之。
- 按注册方式:
- 静态广播:不管程序是否处于活动状态都进行监听,每次触发都建立新的Receiver对象。
- 动态广播:代码中注册,必须取消注册,通常在onDestory()中调用unregisterReceiver()来实现。无论触发几次都使用同一个Receiver对象。
- 按定义方式:
- 系统广播:系统内部特定事件发生时自动发出。
- 自定义广播:应用程序自定义广播。
- 按范围方式:
- 全局广播:可被任意应用程序接收或接收来自任意应用程序的广播。
- 本地广播:只能在应用程序内部进行传递或接收。
广播的使用
创建广播接收器
直接继承BroadcastReceiver创建子类并实现父类的onReceive()方法即可,如下示例代码:
1 | |
静态广播
需在AndroidMainfest文件中定义:
1 | |
说明:
- android:enabled 启用广播
- android:exported 能接收外部APK发送的广播
动态广播
无需AndroidMainfest文件中定义,在需在代码中注册:
1 | |
发送广播
自定义广播的发送方式如下:
1 | |
注:Android 8.0废除大部分静态广播,对于代码需要修改某些部分(发送广播部分需要设置ComponetName):
1 | |
带权限的广播
为避免其他应用监听广播造成数据泄露、冒充发送广播造成混乱,可在AndroidMainfest文件中添加权限:
1 | |
并在发送时指定权限:
sendBroadcast(intent, "com.jeanboy.permissions.MY_BROADCAST");
本地广播
上述BroadcastReceiver用于应用之间的传递消息。
而LocalBroadcast(本地广播)用于应用内部传递消息,其创建仍然是继承BroadcastReceiver创建子类,并实现父类的onReceive()方法。
在注册、发送、注销广播时使用LocalBroadcastManager来进行相关操作,如下:
1 | |
Content Provider
内容提供者的主要作用是各应用间的数据共享,其他Android应用可以使用ContentResolver对象请求执行ContentProvider中的同名方法,如图:
统一资源标识符(URI)
URI代表要操作的数据,用以标识每个ContentProvider,在Android中其格式如下:
URI = <schema>://<authority>/<path>/<id>
<schema>URI前缀,说明由ContentProvider控制数据,是固定形式"content".<authority>唯一标识符以定位ContentProvider,一般是自定义ContentProvider类的完全限定名称。<path>路径片段。<id>记录。
MIME数据类型
MIME是指定某个扩展名的文件用一种应用程序来打开,格式:Type/Subtype
ContentProvider.geType(uri) 根据URI返回MIME类型。
标准MIME
由媒体类型Type和子类型Subtype组成,都很简单,如:text/html
自定义MIME
每个内容类型的Android MIME类型有两种形式:
- 多条记录:
vnd.android.cursor.dir/Subtype - 单条记录:
vnd.android.cursor.item/Subtype
其中,Type是固定的,Subtype按照格式填写。
在使用Intent时,会用到MIME,根据MIME类型打开符合条件的Activity,例如:
1 | |
创建ContentProvider
创建一个继承自ContentProvider的类,并重载onCreate,query,getType,insert,delete,update方法。
然後,在AndroidManifest.xml中注册:
1 | |
使用ContentProvider
获取ContentResolver实例的方法为:
ContentResolver resolver = getContentResolver();
ContentResolver有几个基本数据库操作方法:
1 | |
ContentProvider权限
在AndroidManifest.xml中,如下代码:
1 | |
参数解释:
- exported: 此服务能否被其他组件调用或交互。
- readPermission: 使用ContentProvider里的query()函数的权限。
- writePermission: 修改权限,insert(),update()和delete()函数权限。
- permission: 客户端访问ContentProvider必需的权限名称,此权限会被readPermission和writePermission覆盖。
权限使用:
在AndroidManifest文件的application标签的同级别位置注册permission标签(本应用)或uses-permission标签(第三方应用)以使用权限。