Android四大组件是指 Activity、Service(服务)、BroadcastReceiver(广播)、ContentProvider。
在注册方面,Activity、Service、ContentProvider 必须在 AndroidManifest 中注册,而 BroadcastReceiver 既可以在 AndroidManifest 中注册,也可以通过代码来注册。如下图所示:
Activity 是一种展示型组件,起作用就在于向用户直接展示一个界面,并且接收用户操作信息从而进行交互。Activity 是唯一一种可以直接感知的组件,可以说,在用户看来 Activity 就是一个Android应用的全部。
Activity 启动方式有两种,显式启动和隐式启动:
显式启动
明确指定一个 Activity 组件,正如我们平常大部分时间所使用的方式:(文中全部代码使用Kotlin)startActivity(Intent(this, SampleActivity::class.java))
或者startActivityForResult(Intent(this, SampleActivity::class.java), 0)
隐式启动
指向一个或多个 Activity 组件,隐式启动需要我们再 AndroidManifest 中为 Activity 配置 intent-filter ,比如:
这个时候,我们可以使用如下方法启动 SampleActivity
// 创建Intent,并制定action
val intent = Intent("sampleActivity")
startActivity(intent)`
隐式启动这种方式,相信我们平常也是用的比较多的,比如调用系统拨号功能。
Activity 的启动模式有4种,standard、singleTop、singleTask、singleInstance
关于 Activity 的启动过程,这里就简单文字描述下,就不贴源码了,关于源码的解析,有机会单独记录。
启动 Activity 都是调用 startActivity(ForResult) 方法,所以,就从 startActivity(ForResult) 方法开始:
public void startActivityForResult(@RequiresPermission Intent intent, int requestCode, @Nullable Bundle options)
public ActivityResult execStartActivity( Context who, IBinder contextThread, IBinder token, Activity target, Intent intent, int requestCode, Bundle options, UserHandle user)
,该方法的参数中传入了 mMainThread.getApplicationThread(),它的类型是 ApplicationThread,ApplicationThread 是 ActivityThread 的一个内部类。app.thread.scheduleLaunchActivity(**)
,app.thread 的类型为 IApplicationThread,其实现者是 ActivityThread 中的内部类 ApplicationThread。饶了一大圈,Activity 的启动过程最终回到了 ApplicationThread 中,ApplicationThread 通过 scheduleLaunchActivity 方法来启动 Activity。Service 是一种计算型组件,用于在后台执行耗时操作。由于 Service 组件工作在后台,因此用户无法直接感知到它的存在。
Activity 组件只有一种运行模式,即 Activity 处于启动状态,Service 组件略有不同,它有两种状态:启动状态和绑定状态。
startService(Intent)
方法启动Service。bindService(Intent, ServiceConnection, int)
方法启动 Service。示例代码:startService(Intent(this, SampleService::class.java))
Context 的实现类只有 ContextWrapper,所以该 Service 的启动从 ContextWrapper 的 startService 方法开始:
ActivityManagerNative.getDefault().startService(**)
来启动一个 Service。对于 ActivityManagerNative.getDefault() 这个对象,在 Activity 的启动过程中第 3 点分析了,它实际上就是 AMS (ActivityManagerService),这里就不在重复说明了。需要注意的是,通过 AMS 来启动 Service 的行为是一个远程过程调用。示例代码:
val service = Intent(this, SampleService::class.java)
bindService(service, mServiceConnection, Service.BIND_AUTO_CREATE)
和 startService 一样,bindService 的过程也是从 ContextWrapper 开始的:
ActivityManagerNative.getDefault().bindService(**)
。2.2.1
中的逻辑类似,最终都是通过 ApplicationThread 来完成 Service 实例的创建并执行其 onCreate 方法。和 startService 方式不同的是,Service 的绑定过程会调用 app.thread
的 scheduleBindService 方法。BroadcastReceiver 也叫广播接收者,是一种消息型组件,用于在不同的组件甚至不同的应用之间传递消息。 BroadcastReceiver 同样是用户无感知的。
BroadcastReceiver 的注册方式有两种,静态注册和动态注册。
ContentProvider 是一种数据共享型组件,用于向其它组件甚至其它应用共享数据。由于只是用来组件或者应用间共享数据,用户同样无法直接感知。
一个 ContentProvider 组件内部要实现数据的增删改查四种操作,其内部维持着一份数据集合。这个数据集合有多种实现方式,ContentProvider 本身对其没有任何要求,常见的使用数据库来实现。
上面对Android的四大组件的作用进行了一个大致的说明,由于篇幅原因,这里只简单描述了下 Activity 和 Service 启动过程,找机会再整理下 BroadcastReceiver 和 ContentProvider 的工作过程。
我们知道,Android 应用是可以开启多个进程的,就是在 AndroidManifest 中使用 android:process 属性,比如要给某一 Activity 指定运行进程,则在其 标签中添加 android:process 属性即可。那么,其它的三种组件是否也可以为其指定运行进程呢?也就是说,Android的四大组件是否都可以开启多进程?
这里我大胆假设小心求证下,我先假设都可以,并且开启方式都和 Activity 相同,如果不行的话,再根据问题进行相应调整,并最终得出结论。
demo:
AndroidManifest中注册
MainActivity中启动 Activity、Service,发送广播,访问ContentProvider
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
Log.d("MainActivity", "主进程号为:${getCurProcessName()}")
// 启动 Activity
startActivity(Intent(this, SampleActivity::class.java))
// 启动 Service
val service = Intent(this, SampleService::class.java)
startService(service)
// 发送广播
sendBroadcast(Intent("com.cy.receiver.sample"))
// 访问ContentProvider
val uri = Uri.parse("content://com.cy.multiprocess.SampleContentProvider")
contentResolver.query(uri, null, null, null, null)
}
}
/**
* Context 的扩展方法:获取当前进程号
*/
fun Context.getCurProcessName(): String? {
val pid = android.os.Process.myPid()
val mActivityManager = getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
for (appProcess in mActivityManager.runningAppProcesses) {
if (appProcess.pid == pid) {
return appProcess.processName
}
}
return null
}
最后在各自生命周期方法中打印进程名,运行结果如下:
由图可知,每个组件所运行的进程和主进程都不是同一个,即:Android的四大组件都可以开启多进程。