一、简介
程序的3个核心组件——Activity、services、广播接收器——是通过intent传递消息的。intent消息对于运行时绑定不同的组件是很方便的,这些组件可以是同一个程序也可以是不同的。一个intent对象,是一个被动的数据结构,它保存了一个操作的抽象描述——或通常是一个广播的实例,一些发生的事情的描述,一个通知。传递intent到不同组件的机制是互不相同的。
intent对象是传递给Context.startActivity() 或Activity.startActivityForResult() 以启动Activity或是让一个存在的Activity做些事情。(也可以传递给Activity.setResult()来返回Activity的信息,这个函数叫startActivityForResult()。)
intent对象传递给函数来初始化一个service或是分发一个新的指令给一个正在进行的service。同样,intent传递给来建立一个在调用组件和目标service间的联系。如果一个service没有运行,它可以开始它。
intent可以传递给任何广播函数(如:Context.sendBroadcast()、Context.sendOrderedBroadcast()、 Context.sendStickyBroadcast()),intent被分派给所有感兴趣的广播接收者。很多广播源在系统内核里。
Android系统会寻找合适的Activity、service或设置广播接收器来响应intent,在需要的时候实例化它们。在消息系统里没有交叠:广播intent仅仅分派给广播接收器,不会分派给Activity或service。一个intent分派给startActivity()仅仅分派给Activity,不会分派给service或广播接收器,等等。
Intent有多个属性,每个属性分别表达了不同的意图,同时Intent在启动3大组件时还可以传递数据。
二、Intent的7大属性
Intent七大属性是指Intent的ComponentName、Action、Category、Data、Type、Extra以及Flag,七个属性,总体上可以分为3类:
第一类:启动,有ComponentName(显式),Action(隐式),Category(隐式)。
第二类:传值,有Data(隐式),Type(隐式),Extra(隐式、显式)。
第三类:启动模式,有Flag。
下面看下源码中关于Intent的7大属性的定义:
public class Intent implements Parcelable, Cloneable {
private static final String ATTR_ACTION = "action";
private static final String TAG_CATEGORIES = "categories";
private static final String ATTR_CATEGORY = "category";
private static final String TAG_EXTRA = "extra";
private static final String ATTR_TYPE = "type";
private static final String ATTR_COMPONENT = "component";
private static final String ATTR_DATA = "data";
private static final String ATTR_FLAGS = "flags";
代码一开始便以常量的方式定义了7大属性。
7大属性的具体含义如下:
component(组件):目的组件
action(动作):用来表现意图的行动
category(类别):用来表现动作的类别
data(数据):表示与动作要操纵的数据
type(数据类型):对于data范例的描写
extras(扩展信息):扩展信息
Flags(标志位):期望这个意图的运行模式
三、详解7大属性
1)component
这个组件可以用来指定需要跳转的组件,既可以启动应用内的组件,也可以启动不同应用之间的组件。
3.1应用内启动Activity有两种方式:
3.1.1启动方式1
Intent intent = new Intent();
ComponentName com = new ComponentName(IntentStartSelActivity.this,JumpActivity.class);
intent.setComponent(com);
intent.putExtra("data_type",1);
String string = "这是字符串";
intent.putExtra("data_string", string);
startActivity(intent);
ComponentName构造方法中第一个参数是当前的Activity的上下文,第二个参数是预跳转的类名。
跳转时传递了数据,下面将接收到的数据打印出来:
02-22 15:37:04.508 17337-17337/com.mobile.cdtx.blog D/JumpActivity: textData: data_string:这是字符串
包名:com.mobile.cdtx.blog
类名:com.mobile.cdtx.blog.main.activity.JumpActivity
短类名:.main.activity.JumpActivity
接收数据的方法如下:
Intent intent = getIntent();
String str = intent.getStringExtra("data_string");
ComponentName com = intent.getComponent();
String pkgName = com.getPackageName();//获取包名
String className = com.getClassName();//获取类名
String shortClassName =com.getShortClassName();//短类名
String printString = "data_string:"+str + "\n" + "包名:"+pkgName + "\n" + "类名:"+className+"\n"+"短类名:"+shortClassName;
updateTextView(printString);
Log.d(TAG, "textData: "+printString);
主要是通过intent.getComponent();拿到组件,通过组件可以获取包名,类名等。
3.1.2启动方式2
Intent intent = new Intent();
ComponentName com = new ComponentName("com.mobile.cdtx.blog","com.mobile.cdtx.blog.main.activity.JumpActivity");
intent.setComponent(com);
intent.putExtra("data_type",2);
String string = "这是第二种启动方式字符串";
intent.putExtra("data_string", string);
startActivity(intent);
ComponentName构造方法中第一个参数是包名,第二个参数是预跳完成的类名。如果不知道包名,可以在Android.manifest.xml中查看,如我的代码中的包名如下:
从上面的代码可以看出我的代码的包名是:com.mobile.cdtx.blog
跳转时传递了参数,这里打印下接收到的数据:
02-22 15:51:04.958 30052-30052/com.mobile.cdtx.blog D/JumpActivity: textData: data_string:这是第二种启动方式字符串
包名:com.mobile.cdtx.blog
类名:com.mobile.cdtx.blog.main.activity.JumpActivity
短类名:.main.activity.JumpActivity
接收数据的代码同第一种方式。
3.1.3启动不同应用间的Activity
Intent i = new Intent();
ComponentName comp = new ComponentName("com.android.settings", "com.android.settings.Settings");
i.setComponent(comp);
startActivity(i);
这里调用了手机中默认的设置界面。
ComponentName中的第一个参数是系统应用的设置的包名,第二个参数是设置界面的Activity的名字
系统提供了很多可以直接调用的Activity
下面演示一种:
Intent intent = new Intent(Intent.ACTION_WEB_SEARCH);
intent.putExtra(SearchManager.QUERY,"微信");
startActivity(intent)
以上代码的作用是打开手机中安装的浏览器并搜索"微信",如果手机上安装了多个浏览器,则会弹出一个提示框,让你选择用哪个浏览器打开并进行查询
如果我们想自己实现一个Activity被另一个应用调用,怎么写呢?
首先我们将自己的应用需要被调用的Activity在AndroidManifest.xml的Activity注册中设置action,如下:
Intent intent = new Intent("chroya.foo");
startActivity(intent);
如果使用ComponentName跳转,也是可以的,传包名和类名就可以了
2)action
3.2.1隐式启动Activity
通常,Action、Category属性结合使用,定义这两个属性都是在配置文件的
举例说明:
这里多说两句:intent-filter中只能设置一个action,如果设置多个,则哪个在前执行哪个,但是可以设置多个category
看下即将跳转的界面的配置,action中name的值设置为cat,调用代码如下:Intent intent = new Intent();
intent.setAction("cat");//参数名字可以随便设置
startActivity(intent);
上面的演示是隐式启动Activity,下面说下,显式启动Activity.
关于显式启动和隐式启动的总结:
显式启动:直接指定要跳转的Activity类名,不用过滤,效率高,适用于同一个应用中的不同Activity跳转
隐式启动:需要过滤,相对耗时,但可以找到所有之匹配的应用。适用于不同应用之间的Activity跳转。
3.2.2显式启动Activity
startActivity(new Intent(IntentStartSelActivity.this, JumpActivity.class));
可以看到,通过Intent传递两个参数,第一个参数,当前Activity的上下文,第二个参数即将跳转的类的
3.2.3安卓中提供了多个常用的action
ACTION_MAIN:(android.intent.action.MAIN)Android程序入口。
ACTION_VIEW: (android.intent.action.VIEW) 显示指定数据。
ACTION_EDIT: (android.intent.action.EDIT) 编辑指定数据。
ACTION_DIAL: (android.intent.action.DIAL) 显示拨号面板。
ACTION_CALL: (android.intent.action.CALL) 直接呼叫Data中所带的号码。
ACTION_ANSWER: (android.intent.action.ANSWER) 接听来电。
ACTION_SEND: (android.intent.action.SEND) 向其他人发送数据(例如:彩信/email)。
ACTION_SENDTO: (android.intent.action.SENDTO) 向其他人发送短信。
ACTION_SEARCH: (android.intent.action.SEARCH) 执行搜索。
ACTION_GET_CONTENT: (android.intent.action.GET_CONTENT) 让用户选择数据,并返回所选数据。
这里演示一个调用系统自带的action的例子,如:
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
Uri data=Uri.parse("http://www.baidu.com");
intent.setData(data);
startActivity(intent);
其中Intent.ACTION_VIEW是系统自带的,通过设置数据,调用系统自带的浏览器,如果有多个浏览器,则选择其中一个。然后打开百度的网址。
3)categroy
为Action增加额外的类别信息,Action可以启动多个组件,如果想详细分析要启动的组件,可以通过category进行拦截,任何一个intentFilter中都存在一个默认的intent.CATEGORY_DEFAULT属性
CATEGORY_LAUNCHER意味着在加载程序的时候Activity出现在最上面
CATEGORY_HOME表示页面跳转到HOME界面。也就是主屏幕
常用的属性如下:
CATEGORY_DEFAULT: (android.intent.category.DEFAULT) Android系统中默认的执行方式,按照普通Activity的执行方式执行。
CATEGORY_DEFAULT: (android.intent.category.DEFAULT) Android系统中默认的执行方式,按照普通Activity的执行方式执行。
CATEGORY_HOME: (android.intent.category.HOME) 设置该组件为Home Activity。
CATEGORY_PREFERENCE: (android.intent.category.PREFERENCE) 设置该组件为Preference。
CATEGORY_LAUNCHER: (android.intent.category.LAUNCHER) 设置该组件为在当前应用程序启动器中优先级最高的Activity,通常与入口ACTION_MAIN配合使用。CATEGORY_BROWSABLE: (android.intent.category.BROWSABLE) 设置该组件可以使用浏览器启动。
下面演示下使用categroy跳转到主屏幕的demo
Intent intent=new Intent();
intent.setAction(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_HOME);
startActivity(intent);
以上代码会自动跳转到主屏幕。
4)data
通常用于向Action提供操作的数据,其值为一个Uri对象,Uri的格式如下:scheme://host:port/path
系统中几个内置的Data属性
tel://号码数据格式,后跟电话号码
mailto://邮件数据格式,后跟邮件收件人地址
smsto://短消息数据格式,后跟短信接收号码
content://内容数据格式,后跟需要读取的内容
file://文件数据格式,后跟文件路径
market://search?q=pname:pkgname:市场数据格式,但国内app一般不用。
geo://latitude, longitude:经纬数据格式,在地图上显示经纬度所指定的位置。
data的属性包括:
intent中data属性包括:
android:scheme
用于指定数据的协议部分,如上例中的http部分
android:host
用于指定数据的主机名部分,如上例中的www.baidu.com部分
android:port
用于指定主机名和端口之后的部分,一般紧随在主机名之后
android:mimeType
用于指定可以处理的数据类型,允许使用通配符的方式进行指定
使用举例:
//拨打电话
Intent intent=new Intent();
intent.setAction(Intent.ACTION_CALL);
//提供数据
intent.setData(Uri.parse("tel://110"));
startActivity(intent);
//拨打电话
Intent intent=new Intent();
intent.setAction(Intent.ACTION_DIAL);
//提供数据
intent.setData(Uri.parse("tel://110"));
startActivity(intent);
//查看网站
Intent intent=new Intent();
intent.setAction(Intent.ACTION_VIEW);
//提供数据
intent.setData(Uri.parse("http://www.baidu.com"));
startActivity(intent);
//发送短信
Intent intent=new Intent();
intent.setAction(Intent.ACTION_SENDTO);
//提供数据
intent.setData(Uri.parse("smsto://5556"));
//发送短信的内容
intent.putExtra("sms_body", "hello");
startActivity(intent);
5)type
Type属性用于指定该Data所指定Uri对应的MIME类型,可以是自定义类型,要符合abc/xyz格式的字符串
在使用中与Data属性会相互覆盖,后设置的会把先设置的覆盖掉。
如果设置Type属性需要调用Intent的setDataAndType()方法。
下面提供常用的例子:
//播放视频
Intent intent=new Intent();
intent.setAction(Intent.ACTION_VIEW);
//获得SD卡路径
File sdcard=Environment.getExternalStorageDirectory();
//提供数据
intent.setDataAndType(Uri.fromFile(new File(sdcard, "little-apple.mp4")), "video/*");
startActivity(intent);
//播放音乐
Intent intent=new Intent();
intent.setAction(Intent.ACTION_VIEW);
//获得SD卡路径 /mnt/sdcard/
File sdcard=Environment.getExternalStorageDirectory();
//提供数据/mnt/sdcard/little_apple.mp3
intent.setDataAndType(Uri.fromFile(new File(sdcard, "little_apple.mp3")), "audio/*");
startActivity(intent);
//显示图片
Intent intent=new Intent();
intent.setAction(Intent.ACTION_VIEW);
//获得SD卡路径 /mnt/sdcard/
File sdcard=Environment.getExternalStorageDirectory();
//提供数据
intent.setDataAndType(Uri.fromFile(new File(sdcard, "android.jpg")), "image/*");
startActivity(intent);
//显示文本
Intent intent=new Intent();
intent.setAction(Intent.ACTION_VIEW);
//获得SD卡路径 /mnt/sdcard/
File sdcard=Environment.getExternalStorageDirectory();
//提供数据
intent.setDataAndType(Uri.fromFile(new File(sdcard, "hello.txt")), "text/*");
startActivity(intent);
调用设置界面:intent.setAction("android.setting.SETTINGS");
调用无线网设置界面:intent.setAction("android.setting.WIFI_SETTINGS");
调用系统联系人界面:intent.setAction("com.android.contacts.action.LIST_CONTACTS")
6)extra属性
extra用于多量的数据交换,其对象是一个Bundle对象
通过putExtra(键,值)形式进行数据传递。
内置的Extra常量:
EXTRA_BCC 存放邮件密送人地址的字符串数组
EXTRA_CC 存放邮件抄送人地址的字符串数组
EXTRA_EMAIL 存放邮件地址的字符串数组
EXTRA_SUBJECT 存放邮件主题字符串
EXTRA_TEXT 存放邮件内容
EXTRA_KEY_EVENT 以KeyEvent对象方式存放触发Intent的按键
EXTRA_PHONE_NUMBER 存放调用Action_Call时的电话
使用举例:
Uri uri = Uri.parse("smsto:13200100001");
Intent intent = new Intent();
intent.setAction(Intent. ACTION_SENDTO );
intent.setData(uri);
intent.putExtra("sms_body", "信息内容...");
startActivity( intent );
为Intent添加一些额外的控制旗标,可以通过addFlag()添加控制旗标,来控制Activity的启动效果和启动方式.
使用举例:
Intent intent = new Intent(this, MainActivity.class);
//将Activity栈中处于MainActivity主页面之上的Activity都弹出。
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
常用的属性:
8)启动Activity的其他方式
通过setClass实现跳转
Intent intent = new Intent();
intent.setClass(this,JumpActivity.class);
startActivity(intent);
通过setClassName跳转
Intent intent = new Intent();
intent.setClassName(this,"com.mobile.cdtx.blog.main.activity.JumpActivity");
startActivity(intent);
主界面测试代码:
import android.app.ListActivity;
import android.app.SearchManager;
import android.content.ComponentName;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import java.io.File;
/**
* Created by wangwentao on 2017/2/22.
* 测试Intent组件的7大属性的各种用法
*/
public class IntentStartSelActivity extends ListActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//1.数据源
String[] data = {"component启动方式1","component启动方式2","component跨应用访问","系统可以直接调用的Activity",
"Intent显式启动","Intent隐式启动","调用系统中常用的action","跳转到主屏幕演示","演示data属性","演示type属性",
"演示extra属性","演示flag属性","setClass实现跳转","setClassName跳转方式"};
//2.适配器
@SuppressWarnings("unchecked")
ArrayAdapter arrayAdapter = new ArrayAdapter(this, android.R.layout.simple_list_item_1, data);
//3.绑定
setListAdapter(arrayAdapter);
}
@Override
protected void onListItemClick(ListView l, View v, int position, long id) {
super.onListItemClick(l, v, position, id);
if(0 == id){//component启动方式1
Intent intent = new Intent();
ComponentName com = new ComponentName(IntentStartSelActivity.this,JumpActivity.class);
intent.setComponent(com);
intent.putExtra("data_type",1);
String string = "这是字符串";
intent.putExtra("data_string", string);
startActivity(intent);
}else if(1 == id){//component启动方式2
Intent intent = new Intent();
ComponentName com = new ComponentName("com.mobile.cdtx.blog","com.mobile.cdtx.blog.main.activity.JumpActivity");
intent.setComponent(com);
intent.putExtra("data_type",2);
String string = "这是第二种启动方式字符串";
intent.putExtra("data_string", string);
startActivity(intent);
} else if(2 == id){//component跨应用访问
Intent i = new Intent();
ComponentName comp = new ComponentName("com.android.settings", "com.android.settings.Settings");
i.setComponent(comp);
startActivity(i);
} else if(3 == id){//系统可以直接调用的Activity
Intent intent = new Intent(Intent.ACTION_WEB_SEARCH);
intent.putExtra(SearchManager.QUERY,"微信");
startActivity(intent);
}
else if (4 == id){//Intent显式启动
startActivity(new Intent(IntentStartSelActivity.this, JumpActivity.class));
}else if(5 == id){//Intent隐式启动
Intent intent = new Intent();
intent.setAction("cat");//参数名字可以随便设置
startActivity(intent);
}else if(6 == id){//调用系统中常用的action
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
Uri data=Uri.parse("http://www.baidu.com");
intent.setData(data);
startActivity(intent);
}else if(7 == id){//跳转到主屏幕演示
Intent intent=new Intent();
intent.setAction(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_HOME);
startActivity(intent);
}else if(8 == id){//演示data属性
Intent intent=new Intent();
intent.setAction(Intent.ACTION_CALL);
//提供数据
intent.setData(Uri.parse("tel://123456"));
startActivity(intent);
}else if(9 == id){//演示type属性
Intent intent=new Intent();
intent.setAction(Intent.ACTION_VIEW);
//获得SD卡路径 /mnt/sdcard/
File sdcard= Environment.getExternalStorageDirectory();
//提供数据
intent.setDataAndType(Uri.fromFile(new File(sdcard, "android.jpg")), "image/*");
startActivity(intent);
}else if(10 == id){//演示extra属性
Uri uri = Uri.parse("smsto:12345678901");
Intent intent = new Intent();
intent.setAction(Intent.ACTION_SENDTO );
intent.setData(uri);
intent.putExtra("sms_body", "信息内容...");
startActivity( intent );
}else if(11 == id){//演示flag属性
Intent intent = new Intent(this, MainActivity.class);
//将Activity栈中处于MainActivity主页面之上的Activity都弹出。
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
}else if(12 == id){//setClass实现跳转
Intent intent = new Intent();
intent.setClass(this,JumpActivity.class);
startActivity(intent);
}else if(13 == id){//setClassName跳转方式
Intent intent = new Intent();
intent.setClassName(this,"com.mobile.cdtx.blog.main.activity.JumpActivity");
startActivity(intent);
}
}
}
跳转界面的布局文件
跳转界面的代码
import android.content.ComponentName;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import com.mobile.cdtx.blog.R;
public class JumpActivity extends AppCompatActivity implements View.OnClickListener{
private static final String TAG = "JumpActivity";
Button btnFinish;
TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_jump);
//控件的初始化
initView();
//解析数据
Intent intent = getIntent();
int nType= intent.getIntExtra("data_type",0);
dataFilter(nType,intent);
}
//控件的初始化
private void initView(){
btnFinish = (Button)findViewById(R.id.id_btn_finish);
btnFinish.setOnClickListener(this);
textView = (TextView)findViewById(R.id.id_text);
}
@Override
public void onClick(View v) {
if(v.getId() == R.id.id_btn_finish){
finish();
}
}
//显示不同的数据
private void dataFilter(int type,Intent intent){
switch(type){
case 1:
textData(type,intent);
break;
case 2:
textData(type,intent);
break;
default:
break;
}
}
//更新显示内容
private void updateTextView(String string){
textView.setText(string);
}
//显示component启动方式1数据
private void textData(int type,Intent intent){
String str = intent.getStringExtra("data_string");
ComponentName com = intent.getComponent();
String pkgName = com.getPackageName();//获取包名
String className = com.getClassName();//获取类名
String shortClassName =com.getShortClassName();//短类名
String printString = "data_string:"+str + "\n" + "包名:"+pkgName + "\n" + "类名:"+className+"\n"+"短类名:"+shortClassName;
updateTextView(printString);
Log.d(TAG, "textData: "+printString);
}
}
AndroidManifest.xml中的跳转界面的配置