一.启动 Activity 的分类
在android 种启动4大组件的方式有很多种,但是不管再多,都从调用方式上分为以下2种:
1、显示调用(Intent显示跳转)
显式调用明确指定了调用的组件名称,对于显式调用的Intent,称之为“显式Intent”,如下面的例子:
(1)同一个应用程序中的Activity切换
Intent intent = new Intent(Activity1.this, Activity2.class);
startActivity(intent);
(2)不同应用程序之间的Activity切换
Intent intent = new Intent();
intent.setClassName("com.intent.test.app","com.intent.test.app.SecondActivity");
startActivity(intent);
并且在 com.intent.test.app/.SecondActivity 的 AndroidManifest.xm l要设置如下属性
<activity
android:name=".com.intent.test.app.SecondActivity"
android:exported="true" >
</activity>
2、隐式调用(通过IntentFilter来寻找)
对于没有明确指出目标组件名称的Intent,则称之为“隐式 Intent”。 Android系统使用IntentFilter 来寻找与隐式Intent相关的对象。
在 com.intent.test.app/.SecondActivity 的 AndroidManifest.xm l要设置如下属性
<activity
android:name="com.intent.test.app.SecondActivity"
android:exported="true" >
<intent-filter>
<action android:name="SecondActivity" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
然后在第一个activity 中就可以通过下面的代码来访问了
Intent intent = new Intent("SecondActivity");
startActivity(intent);
3、显示调用跟隐式调用两者的区别
显示调用跟隐式调用两者的区别主要在于以下两点:
(1)显式Intent更多用于在应用程序内部传递消息。比如在某应用程序内,一个Activity启动一个Service。
隐式Intent恰恰相反,它不会用组件名称定义需要激活的目标组件,它更广泛地用于在不同应用程序之间传递消息。
(2)在显式Intent消息中,决定目标组件的唯一要素就是组件名称,因此,如果你的Intent中已经明确定义了目标组件的名称,那么你就完全不用再定义其他Intent内容。 而对于隐式Intent则 不同,由于没有明确的目标组件名称,所以必须由Android系统帮助应用程序寻找与Intent请求意图最匹配的组件。
小结:以上介绍的都是从用法上来介绍Android是如何来启动Activity的,那么接下来我们来分析它的内部原理,显示调用比较简单,所以我就不说了,我主要来介绍隐式调用的原理分析。
二、内部原理分析
这部分我们主要分析隐式调用方式的内部原理。
1、Intent 与组件的匹配
当我们使用隐式调用启动一个Acitivity的时候,Android会将Intent的请求内容和一个叫做IntentFilter的过滤器比较,IntentFilter中包含系统中所有可能的待选组件。如果IntentFilter中某一组件匹配隐式Intent请求的内容,那么Android就选择该组件作为该隐式Intent的目标组件。那么你肯定会问 Android如何知道应用程序能够处理某种类型的Intent请求呢?这就需要我们的应用程序在Android-Manifest.xml中声明自己所含 组件的过滤器(即可以匹配哪些Intent请求)。要明白一个没有声明Intent-Filter的组件只能响应指明自己名字的显式Intent请求,而无法响应隐式Intent请求。而一个声明了IntentFilter的组件既可以响应显式Intent请求,也可以响应隐式Intent请求。那么在比较的过程中,Android系统会用哪些因素作为选择的参考标准呢?答案是:在通过和 IntentFilter比较来解析隐式Intent请求时,Android将以下三个因素作为选择的参考标准。
- Action:使用android:name特性来指定对响应的动作名。
- Data/type:该标签允许你指定组件能作用的数据。
- Category:使用android:category属性来指定在什么样的环境下动作才被响应。每个Intent Filter标签可以包含多个category标签。
- Extras和flag:在解析收到Intent时是并不起作用的
下面我们举个例子来说明一下,比如大家都比较熟悉的打电话,我们就以这个例子来说明一下吧。其实在打电话的时候,我们是使用以下方法:
Uri uri = Uri.parse("tel:23328674");
Intent intent=new Intent(Intent.ACTION_DIAL,uri);
startActivity(intent);
Intent 中定义的ACTION_DIAL为
public static final String ACTION_DIAL = "android.intent.action.DIAL";
那么接下来在我们自己的电话App中,我们需要定义对应的过滤器:
<!-- phone -->
<app-category
settings:category_lable="@string/phone_category_title"
settings:category_icon="@drawable/ic_settings_home"
settings:category_rank="4">
<intent android:action="android.intent.action.DIAL"
android:data="tel:">
<categories android:name="android.intent.category.DEFAULT" />
</intent>
</app-category>
看到这里你是不是对打电话整个流程有一个宏观上的认识呢?其实打电话的整个流程可以这样子理解:
Ams收到StartActivity的请求——>匹配所有组件中的Action——>检查Category来确定是否响应该Intent——>检查作用的数据——>启动组件并传入数据
到这里需要大家注意下面几点细节:
- 隐式调用适用与android的4大组件
- 隐式调用的组件默认category为
category为<category android:name="android.intent.category.DEFAULT"/>,
所以要想能够顺利启动这个组件,最好要加上这个标记
3. 一个组件里可以有多对 只要匹配其中一对,即可启动这个组件。
4. 在里可以有多个 ,只需匹配其中一个即可
5. 在里可以有多个,只需匹配其中一个即可
三、开发中一些常见的隐式调用
1、调用浏览器
Uri uri = Uri.parse("www.baidu.com");
Intent it = new Intent(Intent.ACTION_VIEW,uri);
startActivity(it);
2、调用地图上的某个坐标显示
Uri uri = Uri.parse("geo:56.23467,87.456723");
Intent it = new Intent(Intent.Action_VIEW,uri);
startActivity(it);
3、在地图上显示路径
Uri uri = Uri.parse("http://maps.google.com/maps?f=d&saddr=startLat%20startLng&daddr=endLat%20endLng&hl=en");
Intent it = new Intent(Intent.ACTION_VIEW,URI);
startActivity(it);
4、拨打电话
Uri uri = Uri.parse("tel:1008611");
Intent it = new Intent(Intent.ACTION_DIAL, uri);
startActivity(it);
需要添加权限
<uses-permission id="android.permission.CALL_PHONE" />
5、发送短信
Uri uri = Uri.parse("smsto:10086");
Intent it = new Intent(Intent.ACTION_SENDTO, uri);
it.putExtra("sms_body", "cwj");
startActivity(it);
6、发送彩信
Uri uri = Uri.parse("content://media/external/images/media/11");
Intent it = new Intent(Intent.ACTION_SEND);
it.putExtra("sms_body", "text");
it.putExtra(Intent.EXTRA_STREAM, uri);
it.setType("image/png");
startActivity(it);
7、发送邮件
Uri uri = Uri.parse("mailto:985762@qq.com");
Intent it = new Intent(Intent.ACTION_SENDTO, uri);
startActivity(it);
Intent it = new Intent(Intent.ACTION_SEND);
it.putExtra(Intent.EXTRA_EMAIL,"985762@qq.com");
it.putExtra(Intent.EXTRA_TEXT,"The email body text");
it.setType("text/plain");
startActivity(Intent.createChooser(it, "Choose Email Client"));
Intent it=new Intent(Intent.ACTION_SEND);
String[] tos={"985762@qq.com"};
String[] ccs={"985552@qq.com"};
it.putExtra(Intent.EXTRA_EMAIL, tos);
it.putExtra(Intent.EXTRA_CC, ccs);
it.putExtra(Intent.EXTRA_TEXT, "The email body text");
it.putExtra(Intent.EXTRA_SUBJECT, "The email subject text");
it.setType("message/rfc822");
startActivity(Intent.createChooser(it, "Choose Email Client"));
8、播放音乐
Uri playUri = Uri.parse("file:///sdcard/download/mu.mp3");
returnIt = new Intent(Intent.ACTION_VIEW, playUri);
9、播放媒体文件
Intent it = new Intent(Intent.ACTION_VIEW);
Uri uri = Uri.parse("file:///sdcard/my.mp3");
it.setDataAndType(uri, "audio/mp3");
startActivity(it);
Uri uri = Uri.withAppendedPath(MediaStore.Audio.Media.INTERNAL_CONTENT_URI, "1");
Intent it = new Intent(Intent.ACTION_VIEW, uri);
startActivity(it);
10、安装APK
Uri installUri = Uri.fromParts("package", "xxx", null);
returnIt = new Intent(Intent.ACTION_PACKAGE_ADDED, installUri);