• 进阶之路 | 奇妙的四大组件之旅


    前言

    本文已经收录到我的Github个人博客,欢迎大佬们光临寒舍:

    我的GIthub博客

    学习清单:

    • Activity的工作过程
    • Service的工作过程
    • Service的启动过程
    • Service的绑定过程
    • BroadcastReceiver的工作过程
    • BroadcastReceiver的注册过程
    • BroadcastReceiver的发送和接收过程
    • ContentProvider的工作过程

    一.为什么要学习四大组件?

    何为“四大”:

    • Activity
    • Service
    • BroadcastReceiver
    • ContentProvider

    谈到四大组件,相信在座各位都再熟悉不过了,光闻其名,未见其声,“四大”二字一出,足见其在安卓系统中的地位,可谓是安卓界的F4

    其地位之崇高,在某种程度上也可以体现他的重要性,所以说,光会使用四大组件还是不能体现我们对他的重视(ai hu)的,我们还要分析其工作过程,能够更好地理解系统内部的运行机制,从而加深对Android体系结构的认识;同时,四大组件还是面试必问的知识点之一。

    综上,掌握好四大组件相关的知识,对于一个Android开发者来说是非常重要的!

    以下内容紧张赤鸡,请系好保险带,我们要开车(hu you)了。— No picture,say a J8!

    老司机开车

    二.核心知识点归纳

    2.1 概述

    2.1.1 Activity

    • 类型:展示型组件

    • 作用:展示一个界面并和用户交互

    • 使用:

      A.需要在AndroidManifest中注册

      B.需要借助Intent启动,两种方式:

    • 显示Intent:

      Intent intent=new Intent(xxx.this,xxx.class); startActivity(intent);

    • 隐式Intent:

      Intent intent=new Intent(); intent.setAction(xxx); intent.addCategory(xxx); startActivity(intent);

    • 四种启动模式:
    • standard:标准模式
    • singleTop:栈顶复用模式
    • singleTask:栈内复用模式
    • singleInstance:单实例模式

    想了解启动模式的读者,可以看下笔者写的一篇文章:进阶之路 | 奇妙的Activity之旅中的2.2部分

    • 通过finish()结束一个Activity

    2.1.2 Service

    • 类型:计算型组件

    • 作用:在后台执行一系列计算任务,耗时的后台计算建议在单独的线程中执行

    • 使用:

      A.需要在AndroidManifest中注册

      B.需要借助Intent启动:Intent intent = new Intent(xxx.this, xxx.class); startService(intent);

      C.两种运行状态:

    • 启动状态:通过startService()
    • 绑定状态:通过bindService()

    ​ D.停止方式:unBindService();stopService();

    2.1.3 BroadcastReceiver

    • 类型:消息型组件
    • 作用:在不同的组件乃至不同的应用之间传递消息
    • 使用:
    • 两种注册方式:

      A.动态注册:通过Context.registerReceiver()& Context.unRegisterReceiver(),必须要启动应用才能注册并接收广播。

      B.静态注册:在AndroidManifest文件中注册,不需要启动应用即可接收广播。

    • 需要借助Intent发送广播:Intent intent = new Intent("xxx"); sendBroadcast(intent);

    • 四种广播类型:

      A.普通广播

      B.有序广播

      C.本地广播

      D.粘性广播

    • 没有停止概念

    2.1.4 ContentProvider

    • 类型:共享型组件
    • 作用:向其他组件乃至其他应用共享数据(安卓IPC的一种方式)
    • 使用:
    • 需要在AndroidManifest中注册

    • 无需借助Intent启动

    • 四种操作:注意需要处理好线程同步(因为这些操作运行在Binder线程)

      A.insert():添加数据

      B.update():更新数据

      C.delete():删除数据

      D.query():查询数据

    • 无需手动停止

    想详细了解IPC机制的读者,可以看下笔者写的一篇文章:进阶之路 | 奇妙的 IPC 之旅

    2.2 工作过程

    差不多该进入今天的主题了,为了逼格,为了高薪,大伙往前冲!

    2.2.1 Activity

    Activity启动过程流程图:

    一眼看上去有点晕晕的,墙裂建议配合源码一起服用,效果极佳,笔者推荐一篇文章:图解Activity启动流程,进阶高级

    启动过程

    Q1:结论:

    • ActivityManagerServiceApplicationThread都是Binder
    • Application的创建也是通过Instrumentation来完成的,这个过程和Activity对象一样,都是通过类加载器来实现的
    • Activity的启动过程最终回到ApplicationThread中,通过ApplicationThread.scheduleLaunchActivity() 将启动Activity的消息发送并交由Handler H处理。
    • Handler H对消息的处理会调用handleLaunchActivity()->performLaunchActivity()得以最终完成Activity的创建和启动。

    Q2:重点类

    • Instrumentation

    instrumentationAndroid系统里面的一套控制方法或者”钩子“。 这些钩子可以在正常的生命周期(正常是由操作系统控制的)之外控制Android控件的运行;它们同时可以控制Android如何加载应用程序。

    • ActivityManagerService「AMS」

    AMS是系统的引导服务,应用进程的启动、切换和调度、四大组件的启动和管理都需要AMS的支持。

    • ActivityStackSupervisor:
    • ActivityStackSupervisorAMS中的构造方法中被创建。

    • AMS 通过操作ActivityStackSupervisor来管理Activity

    • ActivityStack:
    • ActivityStack从名称来看是跟栈相关的类,其实它是一个管理类,用来管理系统所有Activity的各种状态
    • 它由ActivityStackSupervisor来进行管理的
    • ApplicationThread:
    • ActivityThread的私有内部类,也是一个Binder对象
    • 在此处它是作为IApplicationThread对象的Server端,等待Client端的请求然后进行处理,最大的Client就是AMS

    2.2.2 Service

    源码流程分析:Service的工作过程

    1.启动过程:

    Service启动过程

    2.绑定过程:

    Service绑定过程

    结论:

    • ContextImplContext的具体实现,通过Activity.attach()Activity建立关联。Activity.attach()中还会完成Window的创建并和Activity&Window的关联,由此事件可传递给Window
    • ActivityServices是一个辅助ActivityManagerService(AMS)进行Service管理的类,包括Service的启动、绑定和停止。
    • Activity类似的,Service的启动/绑定过程最终回到ApplicationThread中,通过ActivityThread.handleCreateService()/ActivityThread.handleBindService完成Service的启动/绑定,注意绑定Service的后续还必须告知客户端已经成功连接Service的这一流程,由ActivityManagerService.publishService()去完成。

    2.2.3 BroadcastReceiver

    源码流程分析:BroadcastReceiver 的工作过程分析

    1.注册

    四大组件的静态注册都是在应用安装时由PackageManagerService(PMS)解析注册,当动态注册BroadcastReceiver时流程为:

    BroadcastReceiver动态注册

    2.发送和接收

    发送和接收流程

    结论:

    • 动态注册广播最终会跨进程交给AMS,并把远程Receiver( 实际上传的是IIntentReceiver,是个Binder 对象)和远程IntentFilter保存起来,完成注册任务
    • 发送广播时,系统为intent添加了两个标记位:
    • FLAG_EXCLUDE_STOPPED_PACKAGES :广播不会发送给已经停止的APP(系统为所有广播默认添加该标记)
    • FLAG_INCLUDE_STOPPED_PACKAGES :广播也会发送到已经停止的APP(两个标记共存时,以该标记为准
    • 最终在ReceiverDispatcher .performReceive ()里回调了ReceiveronReceive(),使得广播得以接收并处理

    Q2:实现原理:

    从实现原理看上,广播使用了观察者模式,基于消息的发布/订阅事件模型

    具体实现流程要点粗略概括如下:

    • 广播接收者BroadcastReceiver通过Binder机制向AMS进行注册
    • 广播发送者通过Binder机制向AMS发送广播
    • AMS查找符合相应条件(IntentFilter/Permission等)的BroadcastReceiver,将广播发送到BroadcastReceiver(一般情况下是Activity)相应的消息循环队列中
    • 消息循环执行拿到此广播,回调BroadcastReceiver中的onReceive()方法

    2.2.4 ContentProvider

    1.启动流程总概

    ContentProvider启动流程总概

    • 启动的入口为ActivityThread.main():创建ActivityThread实例并创建主线程消息队列
    • ActivityThread.attach():远程调用AMS.attachApplication()并提供ApplicationThread用于和AMS的通信
    • AMS.attachApplication():通过ActivityThread.bindApplication()方法和Handler H来调回ActivityThread.handleBindApplication()
    • ActivityThread.handleBindApplication():先创建Application、再加载ContentProvider、最后回调Application.onCreate()
    2.Query过程流程

    insert()delete()update()的实现原理和query()类似,限于篇幅,这里不展开,感兴趣的读者可以主动去探究

    源码流程分析:ContentProvider的工作过程

    3gYU1K.jpg

    结论:

    • ContentProvidermultiprocess属性:ContentProvider是否是单例,一般用单例

    • 访问ContentProvider需要ContentResolver,其真正实现类是ApplicationContentResolver。当ContentProvider所在进程未启动时,第一次访问它会触发ContentProvider的创建以及进程启动

    • ContentProvider所在的进程启动时,会同时被启动并被发布到AMS

    注意:ContentProvider.onCreate()Application.onCreate()执行

    • 同样的,最终通过ActivityThread.handleBindApplication()完成ContentProvider的创建。

    三.课堂小测试

    恭喜你!已经看完了前面的文章,相信你对四大组件已经有一定深度的了解,下面,进行一下课堂小测试,验证一下自己的学习成果吧!

    Q1:为什么要使用ContentProvider?它和SQL在实现上有什么区别?

    • ContentProvider 屏蔽了数据存储的细节,内部实现透明化,用户只需关心URI即可(是否匹配)
    • ContentProvider能实现不同APP的数据共享,SQL只能是自己程序才能访问
    • ContentProvider还能增删本地的文件,XML等信息

    Q2:Android引入四大组件的用意

    这个问题在笔者刚开始学习Android的时候就一直困惑,直到看了一篇Google Android 团队:Dianne Hackborn发表在Google+上的一篇post译文

    见解:Google Android Framework团队决定,不要让一个明确的Main方法作为APP的入口,因为需要让系统对APP怎样运行有更多的控制权,在该系统中,用户永远不需要考虑开启和停止一个APP,而把这些事交给系统去管理。所以他们设计了四大组件以作为APP功能的载体和入口

    • Activity

    一个APP与用户交互的入口

    • BroadcastReceiver
    • 一种让系统在正常的用户流(user flow)之外,传递事件给APP的机制。
    • 最重要的是,因为这是另一个被精心定义的APP的入口,即使APP当前并不在运行,系统也可以将Broadcasts传递给APP
    • Service

    APP由于各种各样的原因需要在后台运行时,Service就是一个这样的入口

    • ContentProvider
    • 人们通常会将它当作对数据库的抽象,因为有许多的API和支持库就是这样使用ContentProvider
    • 但是从系统设计的角度,这并不是ContentProvider的初衷。对于系统来说,ContentProvider实际上是一个入口,用于获取一个APP内部的公开的被命名的数据项(data items),每个数据项都被一个URI scheme所标识。

    如果文章对您有一点帮助的话,希望您能点一下赞,您的点赞,是我前进的动力

    本文参考链接:

  • 相关阅读:
    Java 获取本机IP
    IDEA2017.3.1破解激活
    java访问https绕过证书信任
    windows版nginx+ftp实现图片服务器的搭建
    json转字符串,json转list,json转pojo的工具类
    文件上传到ftp服务工具类
    一个servlet处理多个功能
    一二级栏目的查询
    后台接收URL地址的参数
    SSH邮箱验证与激活
  • 原文地址:https://www.cnblogs.com/xcynice/p/qi_miao_de_si_da_zu_jian_zhi_lv.html
Copyright © 2020-2023  润新知