Intent概述
Intent简介
Intent主要封装了Android应用程序需要启动某个组件的“意图”,亦是应用程序组件之间通信的重要媒介,与程序组件之间进行数据交换。
Intent功能
- 启动Activity
- startActivity(Intent intent)
- startActivityForResult(Intent intent , int requestCode)
- 启动Service
- ComponentName startService(Intent service)
- boolean bindService(Intent service , ServiceConnection conn , int flags)
- 启动BroadcastReceiver
- sendBroadcast(Intent intent)
- sendBroadcast(Intent intent , String receiverPermission)
- sendOrderedBroadcast(Intent intent , String receiverPermission , BroadcastReceiver resultReceiver , Handler scheduler , int initialCode , String initialData , Bundle initialExtras)
- sendOrderedBroadcast(Intent intent)
- sendBroadcast(Intent intent , String receiverPermission)
- sendStickyBroadcast(Intent intent)
- sendStickyOrderedBroadcast(Intent intent , BroadcastReceiver resultReceiver , Handler scheduler , int initialCode , String initialData , Bundle initialExtras)
Intent组成
Intent由7部分信息组成:Component、Action、Data、Category、Extras、Flags、Type。
根据信息的作用又可分为三类:- Component、Action、Data、Category为一类,这4中信息决定了Android会启动哪个组件,其中Component Name用于在显式Intent中使用,Action、Data、Category、Extras、Flags、Type用于在隐式Intent中使用。
- Extras为一类,里面包含了具体的用于组件实际处理的数据信息。
- Flags为一类,其是Intent的元数据,决定了Android对其操作的一些行为,下面会介绍。
Intent类型
一般包含两种类型:显示Intent、隐式Intent。
显式的Intent:Intent中明确包含了要启动的组件的完整类名(包名及类名),那么这个Intent就是显式的。使用显式Intent启动一个组件,那就必须要知道自己的要启动的组件的类名。当创建了一个显式Intent去启动Activity或Service的时候,系统会立即启动Intent中所指定的组件。
隐式的Intent:Intent没有包含要启动的组件的完整类名,那么这个Intent就是即隐式的。虽然隐式的Intent没有指定要启动的组件的类名,但是一般情况下,隐式的Intent都要指定需要执行的action。一般,隐式的Intent只用在当前App中通过Intent启动另一个App的组件的时候,让另一个App的组件接收并处理该Intent。隐式的Intent体现了Android的一种设计哲学:当前App无需具有所有功能,可以通过与其他App组合起来,给用户提供很好的用户体验。而连接自己的App与其他App的纽带就是隐式Intent。当创建了一个隐式Intent去使用的时候,Android系统会将该隐式Intent所包含的信息与设备上其他所有App中manifest文件中注册的组件的Intent Filters进行对比过滤,从中找出满足能够接收处理该隐式Intent的App和对应的组件。如果有多个App中的某个组件都符合条件,那么Android会弹出一个对话框让用户选择需要启动哪个App。
Intent属性及intent-filter配置
Component属性
- Component属性需要接受一个ComponentName对象,该类对象的构造器均需要指定包名和类名,也就直接唯一的确定了一个组件类。
- 指定Component属性的Intent即已经确定了需要启动那个组件,因此该Intent是显式Intent,如果没有指定Component属性,则此Intent是隐式Intent。
- 示例:
public void skipIntentTwoActivity(View source){
// 创建ComponentName对象
ComponentName cn = new ComponentName(IntentOneActivity.this,IntentTwoActivity.class);
Intent intent = new Intent();
// 为Intent设置 Component属性
intent.setComponent(cn);
startActivity(intent);
}
Action、Category属性与intent-filter配置
- Intent的Action、Category属性的值都是一个普通字符串。Action代表Intent所要完成一个抽象的“动作”,而Category则用于为Action增加额外的附加类别信息。
- Intent对象最多只能包含一个Action属性(通过setAction方法设置),但是可以包含多个Category属性(通过addCategory方法设置,也可以不设置,不设置时Category有一个默认值—-android.intent.category.DEFAULT)。
- 示例:
public static final String THREE_ACTION = "com.fpp.androidtestapp.activity.impl.intent.THREE_ACTION";
public void skipIntentThreeActivity(View source){
Intent intent = new Intent();
// 为Intent设置 Action属性
intent.setAction(IntentOneActivity.THREE_ACTION);
// 为Intent设置 Category属性
intent.addCategory("category");
startActivity(intent);
}
<activity android:name=".activity.impl.intent.IntentThreeActivity">
<intent-filter>
<!-- 指定该Activity能响应Action属性值为指定字符串的Intent -->
<action android:name="com.fpp.androidtestapp.activity.impl.intent.THREE_ACTION" />
<!-- 指定该Activity能响应Category属性值为category字符串的Intent -->
<category android:name="category" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
指定Action、Category调用系统Activity
- Intent中提供了大量的Action、Category常量用于启动系统Activity。
- 常见Action常量:
- ACTION_VIEW:查看指定数据
- ACTION_ATTACH_DATA:指定某块数据将被附加到其他地方
- ACTION_EDIT:编辑指定数据
- ACTION_PICK:从列表中选择某项,并返回所选数据
- ACTION_CHOOSER:显示一个Activity选择器
- ACTION_GET_CONTENT:让用户选择数据,并返回所选数据
- ACTION_DIAL:显示拨号面板
- ACTION_CALL:直接向指定用户打电话
- ACTION_SEND:向其他人发送数据
- ACTION_SENDTO:向其他人发送消息
- ACTION_ANSWER:应答电话
- ACTION_INSERT:插入数据
- ACTION_DELETE:删除数据
- ACTION_RUN:运行数据
- ACTION_SYNC:执行数据同步
- ACTION_PICK_ACTIVITY:用于选择Activity
- ACTION_SEARCH:执行搜索
- ACTION_WEB_SEARCH:执行web搜索
- ACTION_FACTORY_TEST:工厂测试入口点
- ACTION_BOOT_COMPLETED:Android系统在启动完毕后发出带有此Action的广播(Broadcast)。
- ACTION_TIME_CHANGED:Android系统的时间发生改变后发出带有此Action的广播(Broadcast)。
- ACTION_PACKAGE_ADDED:Android系统安装了新的App之后发出带有此Action的广播(Broadcast)。
- ACTION_PACKAGE_CHANGED:Android系统中已存在的App发生改变之后(如更新)发出带有此Action的广播(Broadcast)。
- ACTION_PACKAGE_REMOVED:Android系统卸载App之后发出带有此Action的广播(Broadcast)。
- 常见Category常量:
- CATEGORY_DEFAULT:默认Category
- CATEGORY_BROWSABLE:指定该Activity能被浏览器安全调用
- CATEGORY_TAB:指定Activity作为TabActivity的Tab页
- CATEGORY_LAUNCHER:Activity显示顶级程序列表
- CATEGORY_INFO:用于提供包信息
- CATEGORY_HOME:设置该Activity随系统启动而运行
- CATEGORY_PREFERENCE:该Activity是参数面板
- CATEGORY_TEST:该Activity是一个测试
- CATEGORY_CAR_DOCK:指定手机被插入汽车底座(硬件)时运行该Activity
- CATEGORY_DESK_DOCK:指定手机被插入桌面底座(硬件)时运行该Activity
- CATEGORY_CAR_MODE:设置该Activity可在车载环境下使用
- 示例 1:
public void lookOverLinkman(View source) {
Intent intent = new Intent();
// 为Intent设置 Action属性
intent.setAction(Intent.ACTION_GET_CONTENT);
// 为Intent设置 Type属性
intent.setType("vnd.android.cursor.item/phone");
// 启动Activity,希望获取该Activity的结果
startActivityForResult(intent, PICK_CONTACT);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode) {
case PICK_CONTACT:
if (resultCode == Activity.RESULT_OK) {
// 获取返回数据
Uri contactData = data.getData();
CursorLoader cursorLoader = new CursorLoader(
this, contactData, null, null, null, null);
// 查询联系人信息
Cursor cursor = cursorLoader.loadInBackground();
// 如果查询到此联系人
if (cursor.moveToFirst()) {
cursor.getColumnIndex(ContactsContract.Contacts._ID));
// 获取联系人名称
String name = cursor.getString(cursor.getColumnIndexOrThrow(
ContactsContract.Contacts.DISPLAY_NAME));
String phoneNumger = "此联系人暂未输入电话号码!";
// 根据联系人查询该联系人的详细信息
ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null,ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = " + contactId, null, null);
if (phones.moveToFirst()) {
// 取出电话号码
phoneNumger = phones.getString(phones.getColumnIndex(
ContactsContract.CommonDataKinds.Phone.NUMBER));
}
// 关闭游标
phones.close();
etAtvtIntentOneName.setText(name);
etAtvtIntentOneNumber.setText(phoneNumger);
}
// 关闭游标
cursor.close();
}
break;
}
}
- 示例 2:
public void returnHome(View source) {
Intent intent = new Intent();
// 为Intent设置 Action 属性
intent.setAction(Intent.ACTION_MAIN);
// 为Intent设置 Category 属性
intent.addCategory(Intent.CATEGORY_HOME);
// 启动Activity,
startActivity(intent);
}
Data、Type属性与intent-filter配置
- Data属性通常用于向Action属性提供操作的数据。Data属性接受一个Uri对象(Uri字符串:scheme://hose:port/paht)。
- Type属性用于指定该Data属性所指定Uri对应的MIME类型(任何自定义的MIME类型,符合 abc/xyz 格式字符串即可)。
- Data属性和Type属性会相互覆盖。先设置的属性会被后设置的属性覆盖,如果不想被覆盖则使用setDataAndType方法进行设置。
- 示例:
public void overrideType(View source) {
Intent intent = new Intent(this,IntentFourActivity.class);
// 先设置Type属性
intent.setType("abc/xyz");
// 再设置Data属性,此时覆盖了之前设置的Type属性
intent.setData(Uri.parse("zhi://www.fpp.com:8088/test"));
ToastUtils.showLong(this,"intent = " + intent.toString());
}
public void overrideData(View source) {
Intent intent = new Intent(this,IntentFourActivity.class);
// 先设置Data属性
intent.setData(Uri.parse("zhi://www.fpp.com:8088/test"));
// 再设置Type属性,此时覆盖了之前设置的Data属性
intent.setType("abc/xyz");
ToastUtils.showLong(this,"intent = " + intent.toString());
}
public void dataAndType(View source) {
Intent intent = new Intent(this,IntentFourActivity.class);
// 同时设置Data属性和Type属性
intent.setDataAndType(Uri.parse("zhi://www.fpp.com:8088/test"),"abc/xyz");
ToastUtils.showLong(this,"intent = " + intent.toString());
}
- AndroidManifest.xml中Data属性和Type属性声明
- mimeType:用于声明该组件所能匹配的Intent的Type属性
- scheme:用于声明该组件所能匹配的Intent的Data属性的 scheme 部分
- hostL:用于声明该组件所能匹配的Intent的Type属性的 host 部分
- port:用于声明该组件所能匹配的Intent的Type属性的 port 部分
- path:用于声明该组件所能匹配的Intent的Type属性的 path 部分
- pathPrefix:用于声明该组件所能匹配的Intent的Type属性的 path 前缀
- pathPattern:用于声明该组件所能匹配的Intent的Type属性的 path 字符串模板
<data
android:mimeType=""
android:scheme=""
android:host=""
android:port=""
android:path=""
android:pathPrefix=""
android:pathPattern=""
/>
- Data属性匹配过程差异说明
- 如果目标组件的 data 子元素只指定了 android:scheme 属性,那么只要Intent的Data属性的scheme部分与android:scheme属性值相同,即可启动该组件。
- 如果目标组件的 data 子元素只指定了 android:scheme 、android:host 属性,那么只要Intent的Data属性的scheme、host部分与android:scheme、android:host属性值相同,即可启动该组件。
- 如果目标组件的 data 子元素只指定了 android:scheme 、android:host 、android:port 属性,那么只要Intent的Data属性的scheme、host、port部分与android:scheme 、android:host 、android:port属性值相同,即可启动该组件。
- 如果目标组件的 data 子元素只指定了 android:scheme 、android:host 、android:path 属性,那么只要Intent的Data属性的scheme、host、path部分与android:scheme、android:host 、android:path属性值相同,即可启动该组件。
- 如果目标组件的 data 子元素只指定了 android:scheme 、android:host 、android:port 、android:path 属性,那么只要Intent的Data属性的scheme、host、port、path部分依次与android:scheme、android:host 、android:port 、android:path属性值相同,即可启动该组件。
- 示例 1 :
<activity android:name=".activity.impl.intent.IntentFiveActivity">
<intent-filter>
<!-- 指定该Activity能响应Action属性值为指定字符串的Intent -->
<action android:name="xx" />
<!-- 指定该Activity能响应Category属性值默认属性值的Intent -->
<category android:name="android.intent.category.DEFAULT" />
<!-- 指定该Activity的data属性 -->
<data android:scheme="zhi" />
</intent-filter>
</activity>
<activity android:name=".activity.impl.intent.IntentSixActivity">
<intent-filter>
<!-- 指定该Activity能响应Action属性值为指定字符串的Intent -->
<action android:name="xx" />
<!-- 指定该Activity能响应Category属性值默认属性值的Intent -->
<category android:name="android.intent.category.DEFAULT" />
<!-- 指定该Activity的data属性 -->
<data
android:host="www.fpp.com"
android:port="8088"
android:scheme="zhi" />
</intent-filter>
</activity>
<activity android:name=".activity.impl.intent.IntentSevenActivity">
<intent-filter>
<!-- 指定该Activity能响应Action属性值为指定字符串的Intent -->
<action android:name="xx" />
<!-- 指定该Activity能响应Category属性值默认属性值的Intent -->
<category android:name="android.intent.category.DEFAULT" />
<!-- 指定该Activity的data属性 -->
<data
android:host="www.fpp.com"
android:path="/tests"
android:scheme="zhi" />
</intent-filter>
</activity>
<activity android:name=".activity.impl.intent.IntentEightActivity">
<intent-filter>
<!-- 指定该Activity能响应Action属性值为指定字符串的Intent -->
<action android:name="xx" />
<!-- 指定该Activity能响应Category属性值默认属性值的Intent -->
<category android:name="android.intent.category.DEFAULT" />
<!-- 指定该Activity的data属性 -->
<data
android:host="www.fpp.com"
android:path="/tests"
android:port="8088"
android:scheme="zhi" />
</intent-filter>
</activity>
<activity android:name=".activity.impl.intent.IntentNineActivity">
<intent-filter>
<!-- 指定该Activity能响应Action属性值为指定字符串的Intent -->
<action android:name="xx" />
<!-- 指定该Activity能响应Category属性值默认属性值的Intent -->
<category android:name="android.intent.category.DEFAULT" />
<!-- 指定该Activity的data属性 -->
<data
android:host="www.fpp.com"
android:mimeType="abc/xyz"
android:path="/tests"
android:port="8088"
android:scheme="zhi" />
</intent-filter>
</activity>
public void scheme(View source) {
Intent intent = new Intent(this, IntentFiveActivity.class);
// 设置Data属性
intent.setData(Uri.parse("zhi://www.fpps.com:8008/test"));
startActivity(intent);
}
public void schemeHostPort(View source) {
Intent intent = new Intent(this, IntentSixActivity.class);
// 设置Data属性
intent.setData(Uri.parse("zhi://www.fpp.com:8088/test"));
startActivity(intent);
}
public void schemeHostPast(View source) {
Intent intent = new Intent(this, IntentSevenActivity.class);
// 设置Data属性
intent.setData(Uri.parse("zhi://www.fpp.com:8080/tests"));
startActivity(intent);
}
public void schemeHostPastPath(View source) {
Intent intent = new Intent(this, IntentEightActivity.class);
// 设置Data属性
intent.setData(Uri.parse("zhi://www.fpp.com:8088/tests"));
startActivity(intent);
}
public void schemeHostPastPathType(View source) {
Intent intent = new Intent(this, IntentNineActivity.class);
// 设置Data属性
intent.setDataAndType(Uri.parse("zhi://www.fpp.com:8088/tests"),"abc/xyz");
startActivity(intent);
}
- 示例 2 :
/**
* 打开网页
* @param source
*/
public void test(View source) {
Intent intent = new Intent();
String data = "https://www.baidu.com/";
// 根据指定字符串解析出Uri对象
Uri uri = Uri.parse(data);
// 为Intent 设置Action属性
intent.setAction(Intent.ACTION_VIEW);
// 设置Data属性
intent.setData(uri);
startActivity(intent);
}
/**
* 编辑标识为“1”的联系人信息
* @param source
*/
public void edit(View source) {
Intent intent = new Intent();
// 标识为 “1” 的联系人信息
String data = "content://com.android.contacts/contacts/1";
// 根据指定字符串解析出Uri对象
Uri uri = Uri.parse(data);
// 为Intent 设置Action属性(编辑)
intent.setAction(Intent.ACTION_EDIT);
// 设置Data属性
intent.setData(uri);
startActivity(intent);
}
/**
* 拨打电话为“15700001111”----拨号界面
* @param source
*/
public void call(View source) {
Intent intent = new Intent();
String data = "tes:15700001111";
// 根据指定字符串解析出Uri对象
Uri uri = Uri.parse(data);
// 为Intent 设置Action属性
intent.setAction(Intent.ACTION_DIAL);
// 设置Data属性
intent.setData(uri);
startActivity(intent);
}
- Data
- tel://:号码数据格式,后跟电话号码。
- mailto://:邮件数据格式,后跟邮件收件人地址。
- smsto://:短息数据格式,后跟短信接收号码。
- content://:内容数据格式,后跟需要读取的内容。
- file://:文件数据格式,后跟文件路径。
- market://search?q=pname:pkgname:市场数据格式,在Google Market里搜索包名为pkgname的应用。
- geo://latitude, longitude:经纬数据格式,在地图上显示经纬度所指定的位置。
- Type
- MimeType:
{“.3gp”, “video/3gpp”},
{“.apk”, “application/vnd.android.package-archive”},
{“.asf”, “video/x-ms-asf”},
{“.avi”, “video/x-msvideo”},
{“.bin”, “application/octet-stream”},
{“.bmp”, “image/bmp”},
{“.c”, “text/plain”},
{“.class”, “application/octet-stream”},
{“.conf”, “text/plain”},
{“.cpp”, “text/plain”},
{“.doc”, “application/msword”},
{“.docx”, “application/vnd.openxmlformats-officedocument.wordprocessingml.document”},
{“.xls”, “application/vnd.ms-excel”},
{“.xlsx”, “application/vnd.openxmlformats-officedocument.spreadsheetml.sheet”},
{“.exe”, “application/octet-stream”},
{“.gif”, “image/gif”},
{“.gtar”, “application/x-gtar”},
{“.gz”, “application/x-gzip”},
{“.h”, “text/plain”},
{“.htm”, “text/html”},
{“.html”, “text/html”},
{“.jar”, “application/Java-archive”},
{“.java”, “text/plain”},
{“.jpeg”, “image/jpeg”},
{“.jpg”, “image/jpeg”},
{“.js”, “application/x-JavaScript”},
{“.log”, “text/plain”},
{“.m3u”, “audio/x-mpegurl”},
{“.m4a”, “audio/mp4a-latm”},
{“.m4b”, “audio/mp4a-latm”},
{“.m4p”, “audio/mp4a-latm”},
{“.m4u”, “video/vnd.mpegurl”},
{“.m4v”, “video/x-m4v”},
{“.mov”, “video/quicktime”},
{“.mp2”, “audio/x-mpeg”},
{“.mp3”, “audio/x-mpeg”},
{“.mp4”, “video/mp4”},
{“.mpc”, “application/vnd.mpohun.certificate”},
{“.mpe”, “video/mpeg”},
{“.mpeg”, “video/mpeg”},
{“.mpg”, “video/mpeg”},
{“.mpg4”, “video/mp4”},
{“.mpga”, “audio/mpeg”},
{“.msg”, “application/vnd.ms-outlook”},
{“.ogg”, “audio/ogg”},
{“.pdf”, “application/pdf”},
{“.png”, “image/png”},
{“.pps”, “application/vnd.ms-powerpoint”},
{“.ppt”, “application/vnd.ms-powerpoint”},
{“.pptx”, “application/vnd.openxmlformats-officedocument.presentationml.presentation”},
{“.prop”, “text/plain”},
{“.rc”, “text/plain”},
{“.rmvb”, “audio/x-pn-realaudio”},
{“.rtf”, “application/rtf”},
{“.sh”, “text/plain”},
{“.tar”, “application/x-tar”},
{“.tgz”, “application/x-compressed”},
{“.txt”, “text/plain”},
{“.wav”, “audio/x-wav”},
{“.wma”, “audio/x-ms-wma”},
{“.wmv”, “audio/x-ms-wmv”},
{“.wps”, “application/vnd.ms-works”},
{“.xml”, “text/plain”},
{“.z”, “application/x-compress”},
{“.zip”, “application/x-zip-compressed”},
- MimeType:
Extra、Flag属性
- Extras
extras,顾名思义,就是额外的数据信息,Intent中有一个Bundle对象存储着各种键值对,接收该Intent的组件可以从中读取出所需要的信息以便完成相应的工作。有的Intent需要靠Uri携带数据,有的Intent是靠extras携带数据信息。
通过调用Intent对象的各种重载的putExtra(key, value)方法向Intent中加入各种键值对形式的额外数据。也可以直接创建一个Bundle对象,向该Bundle对象传入很多键值对,然后通过调用Intent对象的putExtras(Bundle)方法将其一块设置给Intent对象中去。
Extras常见常量
- EXTRA_BCC:存放邮件密送人地址的字符串数组。
- EXTRA_CC:存放邮件抄送人地址的字符串数组。
- EXTRA_EMAIL:存放邮件地址的字符串数组。
- EXTRA_SUBJECT:存放邮件主题字符串。
- EXTRA_TEXT:存放邮件内容。
- EXTRA_KEY_EVENT:以KeyEvent对象方式存放触发Intent的按键。
- EXTRA_PHONE_NUMBER:存放调用ACTION_CALL时的电话号码。
例如,创建了一个action为ACTION_SEND的Intent对象,然后想用它启动e-mail发送邮件,那么需要给该Intent对象设置两个extra的值:
用Intent.EXTRA_EMAIL 作为key值设置收件方,用Intent.EXTRA_SUBJECT 作为key值设置邮件标题。Intent类里面也指定了很多预定义的EXTRA_*形式的extra,例如上面提到的(Intent.EXTRA_EMAIL 和Intent.EXTRA_SUBJECT)。如果想要声明自己自定义的extra,请确保将App的包名作为extra的前缀,例如:static final String EXTRA_GIGAWATTS = “com.example.EXTRA_GIGAWATTS”;
Flags
flag就是标记的意思,Intent类中定义的flag能够起到作为Intent对象的元数据的作用。这些flag会告知Android系统如何启动Activity(例如,新启动的Activity属于哪个task)以及在该Activity启动后如何对待它(比如)。更多信息可参见Intent的setFlags()方法。
Intent创建Tab页
创建方法
- setContent(Intent intent):直接将指定Intent对应的Activity设置成Tab页的Content。
- 示例:
public class IntentTenActivity extends TabActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_intent_ten);
// 获取Activity中的TabHost组件
TabHost tabHost = getTabHost();
// 使用Intent添加第一个Tab页
tabHost.addTab(tabHost
.newTabSpec("tab1")
.setIndicator("网页展示",getResources().getDrawable(R.drawable.ic_label_black_24dp))
.setContent(new Intent(this,IntentFiveActivity.class))
);
// 使用Intent添加第一个Tab页
tabHost.addTab(tabHost
.newTabSpec("tab2")
.setIndicator("Six")
.setContent(new Intent(this,IntentSixActivity.class))
);
// 使用Intent添加第一个Tab页
tabHost.addTab(tabHost
.newTabSpec("tab3")
.setIndicator("Seven")
.setContent(new Intent(this,IntentSevenActivity.class))
);
}
}