Intent详细解释
Intent是一种意图,用于启动Activity、Service、BroadcastReceiver
类型
方法
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)
sendOrderedBroadcast(Intent intent, String receiverPermission)
右侧的方法都是在Context中(除了startActivityForResult),而且Activity和Service都是Context的子类,就是在Activity和Service中都能启动三大组件

Intent有7个属性:Action、Category、Data、Type、Extra、Flag、Compontent
Intent有两种启动方式:显示启动(指定找XXX)、隐式启动(指定条件,比如是一个大美女)
七大属性
Compontent
适用于显示启动,表示来源(就是上下文参数)和启动的目的地(要启动的组件)
三个构造函数:
ComponentName(String pkg, String cls)
ComponentName(Context pkg, String cls)
ComponentName(Context pkg, Class<?> cls)
启动另外一个App中的Activity
第一个可以用来启动第二个APP中的Activity:
//指定另外一个APP的包名和类名
ComponentName name = new ComponentName("win.haotinayi.animator", "win.haotinayi.animator.MainActivity");
Intent intent = new Intent();
intent.setComponent(name);
startActivity(intent);
注意第二个参数要写全名,这样可以启动包名是win.haotinayi.animator中的MianActivity
启动本App中的Activity
指定上下文和对应的组件名:
ComponentName name = new ComponentName(MainActivity.this, "win.haotinayi.intent.Main2Activity");
//两种方法一个是直接写出全名,一个是写出class
// ComponentName name = new ComponentName(MainActivity.this, Main2Activity.class);
Intent intent = new Intent();
intent.setComponent(name);
startActivity(intent);
简化写法
可以在构造Intent的时候直接写出上下文和类名(只适用显示启动)
Intent intent = new Intent(MainActivity.this, Main2Activity.class);
startActivity(intent);
Category和Action
Action表示一个具体的动作,Categoey是Action增加的额外信息。在隐式启动中要给三个组件添加 子标签而intent-filter子标签可以有action、category、data。Data和Type属性都在data标签内。
即使没有指定特定的Category系统会默认添加一个 的标签。
在intent-filter中可以有多个action和category,但是最多只能有一个data标签,action和category的本质就是一个字符串,用name属性表示,比如主启动Activity:
隐式启动
启动Mian3Activity的代码:
Intent intent = new Intent();
intent.setAction("haotianyi.win");
startActivity(intent);
这时会报错:

这是因为系统默认会给intent添加值是android.intent.category.DEFAULT的category,更改注册文件,可以启动
当两个Activity的注册文件当Action相同,但是category不同,那么只要action和intent匹配就可以启动,AndroidManifest文件:
Activity的启动代码:
Intent intent = new Intent();
intent.setAction("haotianyi.win");
startActivity(intent);
这时候系统会弹出让你选择那一个Activity:

从Intent中获得信息
在Mian2Activity中添加代码,获得当前的ComponentName、Action和Category
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
ComponentName component = getIntent().getComponent();
System.out.println(component.getClassName());
System.out.println(component.getPackageName());
System.out.println(getIntent().getAction());
Set categories = getIntent().getCategories();
// 假如用for循环的话会报错,因为值是null
// 这里的Categeory是Intent携带的而不是Activity注册的Intent
System.out.println(categories);
}

从借助Intent从目标组件返回信息
可以借助Intent从一个组件发送信息到另一个组件(处理信息),另外一个组件返回处理后的值,这样的情景可以使用onActivityForResult方法
启动Activity,第二个参数起到一个标识的作用(从哪里来)
Intent intent = new Intent();
intent.setAction("haotianyi.win");
startActivityForResult(intent,0);
在第二个Activity中,设置结果,setResult参数也起到表示作用(处理结果怎么样)
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
setResult(1);
}
但第二个Activity处理完成并且被finish掉,第一个Activity会回调onActivityForResult方法
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode,resultCode,data);
System.out.println(resultCode);
}

返回桌面
设置Action和Category标签即可
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_HOME);
startActivity(intent);
Extra
Intent额外携带的数据,用putXXX来携带各种类型的数据,用getXXXX来获得数据,更改上面的案例,Activty1的发送代码:
Intent intent = new Intent();
intent.putExtra("hello","你好啊");
intent.setAction("haotianyi.win");
startActivityForResult(intent,0);
Activity2的处理代码,就是给原有数据添加一句话
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
String hello = getIntent().getStringExtra("hello");
hello += "-----这时来自Activity2的问候";
Intent result = getIntent().putExtra("hello", hello);
// 打印Activity2正在处理
System.out.println(getLocalClassName()+"正在处理数据-------"+hello);
setResult(1,result);
}
Activity1的回调代码
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode,resultCode,data);
// 打印结果码
System.out.println(resultCode);
// 打印处理之后的结果
System.out.println(getLocalClassName()+"处理之后的数据是------"+data.getStringExtra("hello"));
}

Data和Type
Intent的Data属性是执行动作的URI和MIME类型,不同的Action有不同的Data数据指定。比如:ACTION_EDIT Action应该和要编辑的文档URI Data匹配,ACTION_VIEW应用应该和要显示的URI匹配。
Intent的Type属性显式指定Intent的数据类型(MIME)。一般Intent的数据类型能够根据数据本身进行判定,但是通过设置这个属性,可以强制采用显式指定的类型而不再进行判定。只要Type负责abc/xyz格式的字符串都可以。
Data和Type在单独指定的时候会相互覆盖,同时指定来两个值使用:setDataAndType方法
Data的匹配规则
Data的参数类型是Uri,例如content://win.hao.ty/data/1
Uri对应的名称是scheme://host/path 三个部分,在host后面可能有port相当于端口号
scheme、host、path是一个范围递减的三个属性(从大到小),就是某一个注册Activity只是指定了scheme属性,那么所有的Intent的Data属性只要以对应字段开头都会匹配
具体匹配实例
有这样三个Activity
对应的Intent如下,分别注释掉不同的赋值语句在启动的时候就会打开几个Activity
Intent intent = new Intent("haotianyi.win");
// 只是启动一个Activity
intent.setData(Uri.parse("hao://"));
// 启动了两个Activity
intent.setData(Uri.parse("hao://tianyi"));
// 启动了三个Activity
intent.setData(Uri.parse("hao://tianyi/datas/1"));
startActivity(intent);
Flag
Flag经常和Activity的启动模式一起来玩,Activity的四种启动模式:
默认模式
standard:不管这个Activity是否在栈中,都执行new操作,假如:栈中顺序是A B C D ,此时D通过Intent跳转到A,那么栈中结构就变成 A B C D A ,点击返回按钮的 显示顺序是 D C B A,依次摧毁。
对应的flag:Intent.FLAG_ACTIVITY_NEW_TASK
当目标Activity的affinity的属性和这个Activity相同时,就完全是默认模式,否则就是在一个新栈的默认模式
SingleTop
singleTop:永远在栈顶,当前Activity D位于栈顶的时候,如果通过Intent跳转到它本身的Activity (即D),那么不会重新创建一个新的D实例,所以栈中的结构依旧为A B C D,如果跳转到B,那么由于B不处于栈顶,所以会新建一个B实例并压入到栈中,结构就变成了A B C D B。
对应flag:FLAG_ACTIVITY_SINGLE_TOP
SingleTask
singleTask:也是永远在栈顶,不过当要启动的D不再栈顶时,会把上面的Activity全部干掉
对应flag:FLAG_ACTIVITY_CLEAR_TOP
SingleInstance
singleInstance:所有栈内只有一个实例,当启动D时,会先新建一个栈,然后再把D入栈
其他flag
FLAG_ACTIVITY_NO_HISTORY 一旦退出,它不会在栈内,比如:原来是A,B,C这个时候再C中以这个FLAG启动D的,D再启动E,这个时候栈中情况为A,B,C,E。