![Android开发实战:从学习到产品](https://wfqqreader-1252317822.image.myqcloud.com/cover/688/920688/b_920688.jpg)
2.3 Intent与Activity之间的跳转
一个Android应用不可能只有一个页面,也就意味着不可能只有一个Activity。既然存在多个Activity,那么多个Activity之间是如何通信的呢?在Android中提供了Intent机制来完成组件之间的通信,本节只讲述如何使用Intent完成Activity之间的通信,其他组件之间的通信等讲述到具体内容时再做叙述。
2.3.1 Intent简介
Intent的中文意思是“意图,意向”,在Android中提供了Intent机制来协助应用间的交互与通信,Intent负责对应用中一次操作的动作、动作涉及数据、附加数据进行描述,Android则负责根据此Intent的描述找到对应的组件,将Intent传递给调用的组件,并完成组件的调用。Intent不仅可用于应用程序之间,也可用于应用程序内部的Activity/Service之间的交互。因此,可以将Intent理解为不同组件之间通信的“媒介”,专门提供组件互相调用的相关信息。
归纳起来,Intent的应用场合主要有以下3种:
• 启动一个Activity。第一种方法是Activity调用startActivity(Intent intent)直接开启一个Activity,第二种方法是通过Activity调用startActivityForResult(Intent intent,int requestCode)启动一个带请求码的Activity,当该Activity结束时将回调原Activity的onActivityResult()方法,并返回一个结果码。
• 启动一个Service,等讲述到具体内容时再做叙述。
• 启动一个Broadcast,等讲述到具体内容时再做叙述。
当使用一个Intent进行组件通信时,需要先实例化一个Intent对象,这时需要设置Intent的属性。Intent的属性设置包括Action(要执行的动作)、Data(执行动作所操作的数据)、Type(显式指定Intent的数据类型)、Category(执行动作的附加信息)、Component(指定Intent目标组件的类名称)、Extras(其他所有附加信息的集合)。下面具体叙述这些属性。
• Action:在SDK中定义了一系列标准动作,其中的一部分如图2-4所示。
![](https://epubservercos.yuewen.com/065DC9/10080940803417301/epubprivate/OEBPS/Images/Figure-P45_66211.jpg?sign=1739285005-0v2rsbVVO1JpwYChT9efrzPjnqYqTeVQ-0-5f04fc1423867cad5b958fdc8c76f8e8)
图2-4 SDK的部分标准动作
其中,ACTION_CALL表示调用拨打电话的应用,ACTION_EDIT表示调用编辑器,ACTION_SYNC表示同步数据。
• Data:在Intent中,Data使用指向数据的URI来表示。比如,在联系人应用中,指向联系人列表的URI是content://contacts/people/。
• Type:对于不同的动作,其URI数据的类型是不同的。通常,Intent的数据类型能够根据数据本身进行判定,但是通过设置这个属性可以强制采用显式指定的类型。
• Category:Category表示执行动作的附加信息。比如,当我们想要让所执行的动作被接收后,作为顶级应用而位于其他所有应用的最上层,并可以使用附加信息LAUNCHER_CATEGORY来实现。
• Component:用于指定Intent目标组件的类名称。通常,Android会根据Intent中所包含的其他属性信息(比如Action、Data/Type、Category)进行查找,并找到一个与之匹配的目标组件。但是,如果我们设置了Component属性,明确指定了Intent目标组件的类名称,那么上述查找过程将不需要执行。
• Extras:可以为组件提供扩展信息。
另外,在使用Intent时,根据是否明确指定Intent对象的接收者,可以分为两种情况。一种是显式的Intent,即在构造Intent对象时就指定接收者;另一种是隐式的Intent,即在构造Intent对象时并不指定接收者。
对于显式的Intent来说,Android不需要解析Intent,因为目标组件已经很明确。对于隐式的Intent来说,Android需要对其进行解析,通过解析将Intent映射给可以处理该Intent的Activity、Service或Broadcast。
Intent解析机制是通过查找注册在AndroidManifest.xml文件中的所有IntentFilter以及IntentFilter所定义的Intent找到最匹配的Intent。
在解析过程中,Android通过判断Intent的Action、Type、Category这3个属性找出最匹配的Intent,具体的判断方法如下:
(1)如果Intent指明了Action,那么目标组件IntentFilter的Action列表中就必须包含有这个Action,否则不能匹配。
(2)如果Intent没有提供Type,那么系统将从Data中得到数据类型。目标组件的数据类型列表中必须包含Intent的数据类型,否则不能匹配。
(3)如果Intent中的数据不是content: URI,而且Intent也没有明确指定它的Type,就将根据Intent中数据的scheme(比如http:或者mailto:)进行匹配。同理,Intent的scheme必须出现在目标组件的scheme列表中,否则不能匹配。
(4)如果Intent指定了一个或多个Category,那么这些类别必须全部出现在目标组件的类别列表中,否则不能匹配。
2.3.2 使用Intent进行Activity跳转
下面我们通过新建一个包含两个Activity的Android工程来实现应用程序内部之间Activity的跳转。除了系统生成的MainActivity,我们再手动新建一个SecondaryActivity。建立Activity的方法是到需要的包下右击,然后单击new→Activity,选择需要的Activity类型即可。此时Android Studio会自动在AndroidManifest.xml中注册,无须手动注册。
1.显式意图
显式意图要求必须知道被激活组件的包和class。如下代码便实现了从MainActivity跳转到SecondaryActivity,并向SecondaryActivity中传递一个字符串的功能。
![](https://epubservercos.yuewen.com/065DC9/10080940803417301/epubprivate/OEBPS/Images/Figure-P47_128625.jpg?sign=1739285005-D8qo0QmeQoRfi4CevlpKugdkGnrQeoET-0-8c8bee318740e5c745e0ac6d094440af)
对activity_main.xml做一些改造:
![](https://epubservercos.yuewen.com/065DC9/10080940803417301/epubprivate/OEBPS/Images/Figure-P47_128626.jpg?sign=1739285005-XOkPr1mJJ6umfeTezMxLWgt1usb9v5v5-0-117b6c3755fed325df215970581f2877)
这里为了跳转方便,使用了一个button按钮,其中findViewById方法已经在前文讲过,是获得View控件对象的方法。button.setOnClickListener()是事件处理的内容,这里不做详细解释,读者只需要像文中一样使用即可,之后重点讲解如何进行事件处理的内容,现在重点关注gotoSecondaryActivity方法。gotoSecondaryActivity方法中的代码使用的各种方法在上一部分有讲述,而注释部分也说明了它们的作用,此处不再分析。仔细分析会发现,使用Intent进行Activity跳转分为两步,第一步构建Intent的对象,第二步调用startActivity方法开启第二个Activity。除了上面给出的构建Intent的对象方法外,还可以直接在实例化Intent对象时在Intent的构造函数中传入第二个Activity类,或者使用setComponent方法传入。而向第二个Activity传递数据除了上面直接用intent对象调用putExtra方法外,还可以使用如下方法:
![](https://epubservercos.yuewen.com/065DC9/10080940803417301/epubprivate/OEBPS/Images/Figure-P48_128628.jpg?sign=1739285005-z0RekGaIoo3rDS2YR55vEcD2NrLhRryb-0-a054d333bd1faf7535d8a5d873eaf5de)
上面给出了如何实现跳转的方法,那么如何在SecondaryActivity中接收数据呢?代码如下:
![](https://epubservercos.yuewen.com/065DC9/10080940803417301/epubprivate/OEBPS/Images/Figure-P48_128629.jpg?sign=1739285005-1xx76iTKn7Wt2fQYuxRB1rQGQGeZrnzF-0-08199c72332b22c93e96f7d59e82a1cb)
为了方便辨识,改造activity_secondary.xml文件:
![](https://epubservercos.yuewen.com/065DC9/10080940803417301/epubprivate/OEBPS/Images/Figure-P49_128631.jpg?sign=1739285005-p4XJUwr1foPEWIPQpiWdi9Y7NARrWKII-0-06e27ea613f4e2f2cf14a281aecb278a)
接收前一个Activity传递来的参数也需要使用Intent。具体来说就是创建Intent对象,使用intent对象来获得一个bundle实例,传递的参数就存储在bundle实例中。这里为了方便使用Log来打印接收过来的数据。
运行程序,如图2-5所示。
点击按钮就会跳转到第二个Activity,如图2-6所示。
![](https://epubservercos.yuewen.com/065DC9/10080940803417301/epubprivate/OEBPS/Images/Figure-P49_66697.jpg?sign=1739285005-n9tqrKxKzL7PsM6qMJnhTayqMRjKhXst-0-9a2fbb4b0cd662cdb239e66bd3d1a829)
图2-5 程序运行显示效果
![](https://epubservercos.yuewen.com/065DC9/10080940803417301/epubprivate/OEBPS/Images/Figure-P49_66698.jpg?sign=1739285005-X2mWsdE3qQyNgkKwEd48LLZjKv79DAeU-0-28ccf68d1f8da452779eded0d6f36ca8)
图2-6 第二个Activity显示的界面
查看Log会发现有如下记录:
![](https://epubservercos.yuewen.com/065DC9/10080940803417301/epubprivate/OEBPS/Images/Figure-P49_66718.jpg?sign=1739285005-FRhLRo5TVID07GB2SyoHUa57IKBeUB1V-0-5d5d321ad24f5bbaa1399a7737247741)
这样就说明应用成功地执行了两个Activity之间的跳转,并且在两个Activity之间进行了数据的传输。
2.隐式意图
隐式意图和显式意图不同,它可以不知道被激活组件的包和class,只通过指定action就进行跳转。同时,被激活的组件必须是在AndroidManifest.xml文件中注册的,注册的方式如下:
![](https://epubservercos.yuewen.com/065DC9/10080940803417301/epubprivate/OEBPS/Images/Figure-P50_128633.jpg?sign=1739285005-m2eGNruFbS2ahnmCPJGpS5hB27kCvohf-0-951be0f8ff0d0f2ab571de51ad7a1e55)
其中的重点就是加入:
![](https://epubservercos.yuewen.com/065DC9/10080940803417301/epubprivate/OEBPS/Images/Figure-P50_128634.jpg?sign=1739285005-X2jXDP6OH4BPtPV8h1pWlXuqO7OuCDjD-0-731fa66c3ed2869a9eaf0f246ae25b07)
除此之外,和显式意图相比,只需要将gotoSecondaryActivity方法中的toSecondary.setClass(this,SecondaryActivity.class)改为toSecondary.setAction("com.buaa.SecondaryActivity")即可,这里的参数内容需要和AndroidManifest.xml文件中注册的内容一致,其他部分都不需要改动。
![](https://epubservercos.yuewen.com/065DC9/10080940803417301/epubprivate/OEBPS/Images/Figure-P50_66782.jpg?sign=1739285005-nTOEvdEdyIdArM2mvulE1P1eofv2e8IC-0-04c33654fab1a837abd5bad8b030305f)
测试的结果也是一样的。读者可能会问,它们如此相像,为什么还需要两种呢?简单来说就是隐式意图可以更好地让代码解耦,使不同模块之间的耦合性更低。另外,如果一个Activity想要启动另一个应用中的Activity就只能使用隐式意图。
3.带回调方法的意图
有时我们需要通过定义在MainActivity中的某一控件来启动SecondaryActivity,并且当SecondaryActivity结束时返给MainActivity一个执行结果。要实现上述功能,只需要完成以下3步即可。
步骤01 在MainActivity中实现向SecondaryActivity发送带请求码的意图,具体实现方法如下(改造MainActivity中的gotoSecondaryActivity方法即可):
![](https://epubservercos.yuewen.com/065DC9/10080940803417301/epubprivate/OEBPS/Images/Figure-P50_128635.jpg?sign=1739285005-L2lnvrtUTKW0QEkZgJPqUhye9fb4Ot2U-0-dd46d26ee91270d50acb143318791a93)
步骤02 在SecondaryActivity中接收toSecondary _request,并向意图中填充要返给MainActivity的内容,最后还需要设置一个返回码。加入一个button按钮,并实现点击时结束SecondaryActivity。改造SecondaryActivity:
![](https://epubservercos.yuewen.com/065DC9/10080940803417301/epubprivate/OEBPS/Images/Figure-P51_128638.jpg?sign=1739285005-GgN61YPMBrEzMEB1ZNE2nZRPKeXuwlMv-0-2d0d562acebc9071d6b6be6774afae96)
在activity_secondary.xml文件中加入一个button按钮:
![](https://epubservercos.yuewen.com/065DC9/10080940803417301/epubprivate/OEBPS/Images/Figure-P51_128639.jpg?sign=1739285005-dsFud9cim13lFbrA1Obi1kufaUL6TTnl-0-bdaffc8884d97a5aa368eb8279bce4fc)
步骤03 结束SecondaryActivity时将返回到MainActivity界面。此时,MainActivity中的onActivityResult()方法将被回调。在本示例中,该方法的具体实现如下:
![](https://epubservercos.yuewen.com/065DC9/10080940803417301/epubprivate/OEBPS/Images/Figure-P51_128640.jpg?sign=1739285005-X93JIjbKOobGpjlqcSN4YOqJJUFIR6ea-0-11d54bd0c43aafa806ae30bda41421a3)
经过上述的3个步骤,运行应用,第二个Activity中会出现一个按钮,点击这个按钮就回到了第一个Activity中。此时在控制台上打开日志,会发现有如下记录:
![](https://epubservercos.yuewen.com/065DC9/10080940803417301/epubprivate/OEBPS/Images/Figure-P52_67016.jpg?sign=1739285005-LsvdYXSaie3tY931U0LqLb7Nm05iKN45-0-6c05e051e1fddd6cde0fab00d422b554)
这样应用就完成了一次带回调方法的跳转。
4.跳转中对象参数的传递
在Android开发中,有时多个Activity之间需要进行对象的传递,使用Intent也可以完成这一功能。具体来说就是将显式跳转或者隐式跳转中的例子做如下修改。
先创建一个User类:
![](https://epubservercos.yuewen.com/065DC9/10080940803417301/epubprivate/OEBPS/Images/Figure-P52_128642.jpg?sign=1739285005-WaDcJ7NEwAP2daDdhrq02zjaW2BtzySV-0-f35965006c093a5068feec45b1545940)
再改造MainActivity中的gotoSecondaryActivity方法:
![](https://epubservercos.yuewen.com/065DC9/10080940803417301/epubprivate/OEBPS/Images/Figure-P52_128643.jpg?sign=1739285005-VRqSe8DCRkJ2Es4VXiy4ZXfd8afWURHn-0-3c1d8aeeb1142fabc442578b441dc19d)
最后改造SecondaryActivity中接收参数的内容为:
![](https://epubservercos.yuewen.com/065DC9/10080940803417301/epubprivate/OEBPS/Images/Figure-P53_128644.jpg?sign=1739285005-ScnFKMGYbtihSxIE3QTbOUEpBXfVtnZl-0-c1cc92828b765b54725474918bbae224)
通过上面的改造,一个在多个Activity之间传递对象参数的应用就完成了。运行应用,点击按钮即可进入第二个Activity,并在日志中出现如下记录:
![](https://epubservercos.yuewen.com/065DC9/10080940803417301/epubprivate/OEBPS/Images/Figure-P53_67218.jpg?sign=1739285005-LnLY79yyLyyjX3aCsXsaYxGpT62QWTyF-0-77b51024a307c8bed9ec1e62ea0ec653)
和我们的预期一致,这说明通过Intent在多个Activity之间传递对象是可行的。
Activity和Intent是Android中非常重要的内容,希望读者在学习完之后多做练习,多加揣摩。