我的编程空间,编程开发者的网络收藏夹
学习永远不晚

从源码剖析Android中的Intent组件

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

从源码剖析Android中的Intent组件

我们知道,Intent主要用来激活安卓几大组件,那么它具体是怎样来激活的?激活时是否可以携带java对象?为何要将对象序列化后才能传递?

一、Intent官网解释
Intent可以被startActivity用来加载Activity,也可以被broadcastIntent发送给指定的BroadReceiver组件,
或者被startService、bingService来与后台service通信。
Intent最主要作用就是加载Activity,好比Activity之间的胶水。
Intent数据结构:

action:所要执行的动作;(例如:ACTION_CALL创建打电话Activity;ACTION_BATTERY_LOW 发出广播警告电池电量低,) data: 要使用的数据(Uri); category:关于目标组件的信息; component:目标组件的类名; extras :这是Bundle数据。

Intent解析:

显式Intent,指定了目标组件的类名,即component,则已知目标组件,不需解析; 隐式Intent,未指定目标组件component,或者不知道、不关心谁来接收Intent,需要Android自己去解析找到目标组件。

隐式Intent解析方法:

1.在AndroidManifest.xml里所有<intent-filter>及其中定义的Intent;
2.通过PackageManager(获取当前设备所安装的应用程序package)查找能处理这个Intent的component。匹配Action、type、category三个变量来寻找。
二、简单解释:
Intent可以激活Andorid的三大组件:Activity、Service和BroadcastReceiver。使用Intent时一般要显式指定目标组件,若未指定则要根据Intent附带的action、type、category三个值来解析,查找能处理的组件。

三、问题:Intent如何实现组件的切换,具体流程?
1、基本方法:(以启动Activity为例)


Intent i = new Intent(MainActivity.this, TargetActivity.class);
startActivity(i);

2、实例化Intent:



public Intent(Context packageContext, Class cls) {
//创建一个组件并赋值给Intent的Component成员
  mComponent = new ComponentName(packageContext, cls);
}

3、启动Activity


startActivity(i) ->
startActivity(Intent intent, @Nullable Bundle options)->
startActivityForResult(intent, -1, options)

public void startActivityForResult(Intent intent, int requestCode, @Nullable Bundle options) {
if (mParent == null) { //如果没有父Activity;Instrumentation是用来与程序指南清单AndroidManifest文件交互的。
  Instrumentation.ActivityResult ar =
  mInstrumentation.execStartActivity(this, mMainThread.getApplicationThread(), mToken, this,intent, requestCode, options); //执行startActivity命令
..... 
} else { //如果有父Activity
   if (options != null) {
     mParent.startActivityFromChild(this, intent, requestCode, options);
   } .....
}

4、执行startActivity命令核心代码:
启动Activity的任务交给了底层ActivityManagerNative来做。


intent.migrateExtraStreamToClipData(); //将intent里的bundle数据进行处理以便给底层处理
intent.prepareToLeaveProcess(); //准备离开应用程序进程,进入ActivityManagerService进程(意味着bundle的数据要在进程间传递)
int result = ActivityManagerNative.getDefault().startActivity(whoThread,   
who.getBasePackageName(), intent,
intent.resolveTypeIfNeeded(who.getContentResolver()),
token, target != null ? target.mEmbeddedID : null,
requestCode, 0, null, options); //调用系统的activity manager服务来启动新的Activity。考虑如果是显式Intent,则直接找对对应的组件类(此处是Activity组件);如果是隐式Intent,为指定目标组件类名,则自动去Application->system搜索合适的组件来处理。
//todo:具体的系统级代码下次进行分析

四、核心问题:为何Intent不能直接在组件间传递对象而要通过序列化机制?
根据上面代码可以看到,Intent在启动其他组件时,会离开当前应用程序进程,进入ActivityManagerService进程(intent.prepareToLeaveProcess()),这也就意味着,Intent所携带的数据要能够在不同进程间传输。首先我们知道,Android是基于Linux系统,不同进程之间的java对象是无法传输,所以我们此处要对对象进行序列化,从而实现对象在 应用程序进程 和 ActivityManagerService进程 之间传输。
而Parcel或者Serializable都可以将对象序列化,其中,Serializable使用方便,但性能不如Parcel容器,后者也是Android系统专门推出的用于进程间通信等的接口。

附加知识:
在不同进程之间,常规数据类型可以直接传递,如整数,以传递字符串为例,要从A进程传递到B进程,只需在B进程的内存区开辟一样大小的空间,然后复制过去即可。
但是,对象却不能直接跨进程传递。即使成员变量值能传递过去,成员方法是无法传递过去的,此时如果B进程要调用成员方法则出错。
具体传递对象的方法:
1. 在进程A中把类中的非默认值的属性和类的唯一标志打成包(这就叫序列化);
2. 把这个包传递到进程B;
3. 进程B接收到包后,根据类的唯一标志把类创建出来(java反射机制);
4. 然后把传来的属性更新到类对象中。
这样进程A和进程B中就包含了两个完全一样的类对象。

五、Intent如何实现对象传递?
Object implements Serializable {...};bundle.putSerializable(Key, Object);
Object implements Parcelable {...} ; bundle.putParcelable(Key, Object);
Serializable接口:这是Java的序列化技术,将Java对象序列化为二进制文件。让对象实现Serializable接口,使用ObjectInputStream 和 ObjectOutputStream 进行对象读写。
Parcelable接口:这是Android提供的用作封装数据的容器,封装后的数据可以通过Intent或IPC来传递。只有基本类型和实现了Parcelable接口的类才能被放入Parcel中。
六、Serializable接口 - Java
属于java序列化机制:只需让java类实现该接口,不用实现任何方法,即可标记该类可序列化。


class Person implements Serializable {...}
Person per = new Person();
bundle.putSerializable("person", per); //传递Person对象的引用
Person mPerson = (Person)getIntent().**getSerializableExtra**("person");

注意:如果此处序列化类Person内部包含其他类(如:PersonInfo)的引用,如:


class Person implements Serializable {
   PersonInf**o info;
}

那么所引用的类必须也可序列化,即实现Serializable接口。因为Person对象在序列化过程中,也会对成员变量序列化。

七、Parcelable接口 - Android
此处围绕 - Android中如何使用Parcel实现对象的传递 - 简单介绍一下原因。
首先要了解Android里面的Parcel容器。

Parcel是一个容器,用来存储可通过IBindler传送的消息(数据或对象引用)。
主要用于轻量级、高性能IPC进程间通信的消息容器。在Android里,一个“process”是一个标准Linux进程,一般而言一个进程无法接触到另一个进程的内存区。而通过Parcel,Android系统会将对象分解成可序列化与反序列化,从而实现进程间通信。
不过,Parcel同样可用于进程内通信,主要实现在应用程序的不同组件之间传递数据。例如,我们可以使用Intent封装Parcel对象在Activity之间传递。
简单来说,Parcel容器实现了进程内与进程间通信,而且还能实现远程调用。

组件间传递对象的具体方法:

让要传递的对象所属类实现 Parcelable 接口;
实现 describeContents 方法;
实现抽象方法 writeToParcel,用于获取对象的当前状态并写入一个Parcel容器中;
给该目标类添加一个静态域 CREATOR ,它是一个实现了Parcelable.Creator接口的对象;
添加一个参数为一个Parcel对象的构造函数,CREATOR会调用这个构造函数来重新改造我们的对象。
问题:
为什么已经有了Java的Serializable接口还要创建一个Parcelable接口?
性能
虽然Parcelable使用起来更复杂一点,但是它的性能更好。

Parcelable的限制:

当使用Parcelable来传递图片Bitmap时不太理想,虽然Bitmap也实现了Parcelable接口。比较优的方法是传递
Parcelable不能用来当做常规的序列化存储,因为Android系统版本不同,Parcelable的具体实现方法也不完全一样,可能导致无法读取Parcel数据。

您可能感兴趣的文章:Android中使用IntentService创建后台服务实例android教程之intent的action属性使用示例(intent发短信)Android Intent的几种用法详细解析Android学习笔记--Activity中使用Intent传值示例代码Android系列之Intent传递对象的几种实例方法android中Intent传值与Bundle传值的区别详解Android组件间通信--深入理解Intent与IntentFilterAndroid Intent启动别的应用实现方法Android 使用Intent传递数据的实现思路与代码详解Android应用开发中Intent的作用及使用方法


免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

从源码剖析Android中的Intent组件

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

从源码剖析Android中的Intent组件

我们知道,Intent主要用来激活安卓几大组件,那么它具体是怎样来激活的?激活时是否可以携带java对象?为何要将对象序列化后才能传递? 一、Intent官网解释 Intent可以被startActivity用来加载Activity,也可以
2022-06-06

源码剖析Android中Okio的使用

这篇文章主要将从源码出发,带大家剖析一下Android中Okio的具体使用,文中的示例代码讲解详细,具有一定的借鉴价值,感兴趣的小伙伴可以了解一下
2023-02-17

Android Jetpack 组件LiveData源码解析

这篇文章主要为大家介绍了Android Jetpack 组件LiveData源码解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
2023-03-10

Android Jetpack组件Lifecycle源码解析

这篇文章主要为大家介绍了Android Jetpack组件Lifecycle源码解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
2023-03-13

Android Jetpack组件LiveData源码分析

本篇内容主要讲解“Android Jetpack组件LiveData源码分析”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Android Jetpack组件LiveData源码分析”吧!基本使用
2023-07-05

从源码解析Android中View的容器ViewGroup

这回我们是深入到ViewGroup内部\,了解ViewGroup的工作,同时会阐述更多有关于View的相关知识。以便为以后能灵活的使用自定义空间打更近一步的基础。希望有志同道合的朋友一起来探讨,深入Android内部,深入理解Androi
2022-06-06

源码分析Django的message组件

这篇文章主要介绍了源码分析Django的message组件,本文通过示例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
2023-05-18

Vue组件中的自定义事件源码分析

这篇文章主要介绍“Vue组件中的自定义事件源码分析”,在日常操作中,相信很多人在Vue组件中的自定义事件源码分析问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Vue组件中的自定义事件源码分析”的疑惑有所帮助!
2023-06-29

从源码分析Android的Volley库的工作流程

Volley现在已经被官方放到AOSP里面,已经逐步成为Android官方推荐的网络框架。 类抽象 对Http协议的抽象 Requeset 顾名思义,对请求的封装,实现了Comparable接口,因为在Volley中是可以指定请求的优先级的
2022-06-06

源码剖析Golang中map扩容底层的实现

之前的文章详细介绍过Go切片和map的基本使用,以及切片的扩容机制。本文针对map的扩容,会从源码的角度全面的剖析一下map扩容的底层实现,需要的可以参考一下
2023-03-06

源码解析AndroidJetpack组件之ViewModel的使用

Jetpack是一个丰富的组件库,它的组件库按类别分为4类,分别是架构(Architecture)、界面(UI)、行为(behavior)和基础(foundation)。本文将从源码和大家讲讲Jetpack组件中ViewModel的使用
2023-05-17

详解Android中通过Intent类实现组件间调用的方法

Intent是Android中用来调用其它组件的类,通过Intent,我们可以非常方便的调用Activity,Broadcast Receiver和Service。Intent intent = new Intent(Intent.ACTI
2022-06-06

从源代码分析Android Universal ImageLoader的缓存处理机制

通过本文带大家一起看过UIL这个国内外大牛都追捧的图片缓存类库的缓存处理机制。看了UIL中的缓存实现,才发现其实这个东西不难,没有太多的进程调度,没有各种内存读取控制机制、没有各种异常处理。反正UIL中不单代码写的简单,连处理都简单。但是这
2022-06-06

Android Jetpack 从使用到源码深耕【调度任务组件WorkManager 从实践到原理 】(一)

本文,我们对Jetpack的调度任务组件WorkManager ,由使用入手,对其源码进行深入学习、总结一下。 1.问题 研究这个框架之前,我们基于自己已有的知识体系,想一些问题,给自己设定一些目标,带着目标和问题,去阅读这块的源码,相信收
2023-08-17

Android Jetpack 从使用到源码深耕【调度任务组件WorkManager 从实践到原理 】(三)

本文,是Jetpack 调度任务组件WorkManager 从实践到原理系列文章的最后一篇,本文我们将对WorkManager 任务的具体执行源码,进行深入的解读。 大家坐好,我们要开始飙车了。 1.任务的具体执行 书接上文,我们既
2023-08-18

揭秘 VUE 组件的神秘面纱:从本质到应用,全面剖析

VUE 组件是 VUE.js 框架的核心概念之一,通过使用组件可以将复杂的应用拆分为更小的可重用和可组合的部分,提高代码的复用性和可维护性。本文将从本质到应用,全面剖析 VUE 组件,帮助您深入了解其工作原理和使用方式。
揭秘 VUE 组件的神秘面纱:从本质到应用,全面剖析
2024-02-26

编程热搜

  • Android:VolumeShaper
    VolumeShaper(支持版本改一下,minsdkversion:26,android8.0(api26)进一步学习对声音的编辑,可以让音频的声音有变化的播放 VolumeShaper.Configuration的三个参数 durati
    Android:VolumeShaper
  • Android崩溃异常捕获方法
    开发中最让人头疼的是应用突然爆炸,然后跳回到桌面。而且我们常常不知道这种状况会何时出现,在应用调试阶段还好,还可以通过调试工具的日志查看错误出现在哪里。但平时使用的时候给你闹崩溃,那你就欲哭无泪了。 那么今天主要讲一下如何去捕捉系统出现的U
    Android崩溃异常捕获方法
  • android开发教程之获取power_profile.xml文件的方法(android运行时能耗值)
    系统的设置–>电池–>使用情况中,统计的能耗的使用情况也是以power_profile.xml的value作为基础参数的1、我的手机中power_profile.xml的内容: HTC t328w代码如下:
    android开发教程之获取power_profile.xml文件的方法(android运行时能耗值)
  • Android SQLite数据库基本操作方法
    程序的最主要的功能在于对数据进行操作,通过对数据进行操作来实现某个功能。而数据库就是很重要的一个方面的,Android中内置了小巧轻便,功能却很强的一个数据库–SQLite数据库。那么就来看一下在Android程序中怎么去操作SQLite数
    Android SQLite数据库基本操作方法
  • ubuntu21.04怎么创建桌面快捷图标?ubuntu软件放到桌面的技巧
    工作的时候为了方便直接打开编辑文件,一些常用的软件或者文件我们会放在桌面,但是在ubuntu20.04下直接直接拖拽文件到桌面根本没有效果,在进入桌面后发现软件列表中的软件只能收藏到面板,无法复制到桌面使用,不知道为什么会这样,似乎并不是很
    ubuntu21.04怎么创建桌面快捷图标?ubuntu软件放到桌面的技巧
  • android获取当前手机号示例程序
    代码如下: public String getLocalNumber() { TelephonyManager tManager =
    android获取当前手机号示例程序
  • Android音视频开发(三)TextureView
    简介 TextureView与SurfaceView类似,可用于显示视频或OpenGL场景。 与SurfaceView的区别 SurfaceView不能使用变换和缩放等操作,不能叠加(Overlay)两个SurfaceView。 Textu
    Android音视频开发(三)TextureView
  • android获取屏幕高度和宽度的实现方法
    本文实例讲述了android获取屏幕高度和宽度的实现方法。分享给大家供大家参考。具体分析如下: 我们需要获取Android手机或Pad的屏幕的物理尺寸,以便于界面的设计或是其他功能的实现。下面就介绍讲一讲如何获取屏幕的物理尺寸 下面的代码即
    android获取屏幕高度和宽度的实现方法
  • Android自定义popupwindow实例代码
    先来看看效果图:一、布局
  • Android第一次实验
    一、实验原理 1.1实验目标 编程实现用户名与密码的存储与调用。 1.2实验要求 设计用户登录界面、登录成功界面、用户注册界面,用户注册时,将其用户名、密码保存到SharedPreference中,登录时输入用户名、密码,读取SharedP
    Android第一次实验

目录