Android意图-Intent详解
Android意图-Intent详解
Intent是Android应用里各组件之间通信的重要方式,一个Activity通过Intent来表达自己的意图—想要启动哪个组件(activity,service,broadcasts)。
一、Intent启动不同组件的方法:
1.Activity
- startActivity()
- startActivityForResult()
2.Service
- startService()
- bindService()
3.Broadcasts
- sendBroadcast()
- sendOrderedBroadcast()
- sendStickyBroadcast()
二、Intent属性与过滤器
Intent属性:
- action
- data
- category
- type
- component
- extras
1.action
描述Intent对象要实施的动作,可以调用Intent#setAction()方法来指定action。action值为String类型。
清单文件中也有:
<action android:name="android.intent.action.MAIN" />
常见的action:
- ACTION_MAIN:值为”android.intent.action.MAIN”,表示整个程序的入口
- ACTION_VIEW:值为”android.intent.action.VIEW”,表示用于将一些数据显示给用户
- ACTION_EDIT:表示允许用户对一些数据进行编辑
- ACTION_DIAL:表示打电话面板
- ACTION_CALL:表示直接拨打电话
- ACTION_SEND:表示发送短信
- ACTION_SENDTO:表示选择发送短信
- ACTION_BATTERY_LOW:表示电量低广播
2.data
Intent对象中用于进行操作的数据,可以调用Intent#setData()或Intent#setDataAndType(),data值一般为Uri类型。
3.category
描述Intent对象中的action属性属于哪个类别,也就是设置Intent对象进行某项操作时的约束,可以通过Intent#addCategory()方法设置,category值为String类型。
如清单文件中:
<category android:name="android.intent.category.LAUNCHER" />
4.type
用于描述组件能够处理的请求类型(即数据的MIME类型),可以通过Intent#setType()或Intent#setDataAndType()来进行设置。type值为String类型。
5.component
描述Intent对象中所使用的组件类名字可以通过Intent#setComponent()方法利用类名进行设定,也可以通过Intent#setClass()方法利用类型对象信息进行设置。当调用组件明确指定了component信息,组件管理服务就不再需要根据action、data、等信息去寻找满足其需求的组件,只需要按照component信息实例化对应的组件作为功能的实现者即可。一但指定了component,intent就变成了单纯的信息载体,只负责传递信息和数据。这种方式通常用于内部组件的互连互通中。component值类型为ComponentName类型。
Intent类中的相关方法:
public Intent setClass(Context packageContext, Class<?> cls) {
mComponent = new ComponentName(packageContext, cls);
return this;
}
public Intent setClassName(String packageName, String className) {
mComponent = new ComponentName(packageName, className);
return this;
}
public Intent setComponent(ComponentName component) {
mComponent = component;
return this;
}
ComponentName
特定应用程序组件(Android四大组件)的标识符。需要在这里封装的两条信息来标识组件:它所在的包(String)和该包中的类(String)名称。
private final String mPackage;
private final String mClass;
public ComponentName(String pkg, String cls) {
if (pkg == null) throw new NullPointerException("package name is null");
if (cls == null) throw new NullPointerException("class name is null");
mPackage = pkg;
mClass = cls;
}
public ComponentName(Context pkg, Class<?> cls) {
mPackage = pkg.getPackageName();
mClass = cls.getName();
}
public ComponentName(Context pkg, String cls) {
if (cls == null) throw new NullPointerException("class name is null");
mPackage = pkg.getPackageName();
mClass = cls;
}
6.extras
以Bundle类的形式存储其他额外的需要的数据。可以通过Intent#putExtras()方法来设置。
public Intent putExtras(Bundle extras) {
if (mExtras == null) {
mExtras = new Bundle();
}
mExtras.putAll(extras);
return this;
}
Intent过滤器
在清单文件中一定见过标签,这就是描述该Activity能够处理哪些Intent的过滤器。一个Activity中可以有一到多组过滤器,每组过滤器通常包括有action、category、type等属性信息。
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
三、Intent类中的构造方法与Intent使用的两种形式:
1.Intent类中的构造方法
/**
* Create an empty intent.
*/
public Intent() {
}
/**
* Copy constructor.
*/
public Intent(Intent o)
public Intent(String action)
public Intent(String action, Uri uri)
public Intent(Context packageContext, Class<?> cls)
public Intent(String action, Uri uri,
Context packageContext, Class<?> cls)
2.获取Intent实例
//方式一(显式):使用上面第五种构造方法:指定当前activity和要打开的activity
Intent intent=new Intent(this,SecondActivity.class);
//方式二(显式):通过使用Intent#setClass()方法指定当前activity和要打开的activity
Intent intent=new Intent();
intent.setClass(this,SecondActivity.class);
//方式三 (隐式):通过使用Intent#setClassName()方法指定当前activity和要打开的activity
Intent intent=new Intent();
intent.setClassName(this,"包名.SecondActivity");
//或者
intent.setClassName("包名","包名.SecondActivity");
3.Intent使用的两种形式:
- 显式
- 隐式
显式
- 直接使用Intent的构造方法传入类名(类名.class),构造出Intent实例。
- 使用Intent#setClass()方法利用类型对象信息进行设置
隐式
先创建出一个Intent实例不指定其对应的Activity组件,再调用Intent#setAction()等方法设置action、category、type等属性信息。由Android系统根据属性信息选择最适合的Activity去运行这个Intent。兼具弱耦合的特性,更灵活。
-
一个Activity如果需要隐式跳转,那么在清单文件中必须添加以下子节点
<intent-filter > <action android:name="com.jeff.action"/> <category android:name="android.intent.category.DEFAULT"/> </intent-filter>
- action节点的name是自己定义的,定义好之后,这个name的值就会成为这个activity动作,在隐式启动Activity时,意图中设置的action必须跟”com.jeff.action”是完全匹配的。
应用场景
- 显式意图:启动同一个应用中的Activity
- 隐式意图:启动不同应用中的Activity
- 在启动效率上,隐式远远低于显式
- 如果系统中有多个Activity与意图设置的Action匹配,那么在启动Activity时,会弹出一个对话框,里面包含所有匹配的Activity。
启动Service的一个异常
“java.lang.IllegalArgumentException: Service Intent must be explicit”
产生原因:API21以后启动Service的Intent必须为显式否则会抛出异常
解决方法:
Intent eintent = new Intent(createExplicitFromImplicitIntent(this,intent));
/***
* API21以后启动Service的Intent必须为显式否则会抛出异常
* "java.lang.IllegalArgumentException: Service Intent must be explicit"
* Android L (lollipop, API 21) introduced a new problem when trying to invoke implicit intent,
* "java.lang.IllegalArgumentException: Service Intent must be explicit"
*
* 该方法可以将隐式Intent转换为显式
* If you are using an implicit intent, and know only 1 target would answer this intent,
* This method will help you turn the implicit intent into the explicit form.
*
* Inspired from SO answer: http://*.com/a/26318757/1446466
* @param context
* @param implicitIntent - The original implicit intent
* @return Explicit Intent created from the implicit original intent
*/
public static Intent createExplicitFromImplicitIntent(Context context, Intent implicitIntent) {
// Retrieve all services that can match the given intent
PackageManager pm = context.getPackageManager();
List<ResolveInfo> resolveInfo = pm.queryIntentServices(implicitIntent, 0);
// Make sure only one match was found
if (resolveInfo == null || resolveInfo.size() != 1) {
return null;
}
// Get component info and create ComponentName
ResolveInfo serviceInfo = resolveInfo.get(0);
String packageName = serviceInfo.serviceInfo.packageName;
String className = serviceInfo.serviceInfo.name;
ComponentName component = new ComponentName(packageName, className);
// Create a new intent. Use the old one for extras and such reuse
Intent explicitIntent = new Intent(implicitIntent);
// Set the component to be explicit
explicitIntent.setComponent(component);
return explicitIntent;
}
四、使用Intent在组件之间传递数据
1.使用Intent传递数据
//传递几种基本的数据类型:
public Intent putExtra(String name, XXX value)
//将src中的所有extras复制到此intent
public Intent putExtras(Intent src)
//传递Bundle类型的数据
public Intent putExtras(Bundle extras)
2.在intent启动的Activity获取传递的数据
//1.首先获取启动这个Activity的intent对象,在Activity类中定义了这样的方法:
/** Return the intent that started this activity. */
public Intent getIntent() {
return mIntent;
}
2.获取到intent对象后使用Intent类中定义的下面两种方法获取传递的数据:
//获取所有类型的数据,获取后强制转换类型即可
public Object getExtra(String name) {
return getExtra(name, null);
}
//获取XXX类型的数据
public XXX getXXXExtra(String name)
//获取Bundle类型的数据
public Bundle getExtras()
上一篇: Java中使用jaxp工具以dom方式对xml进行解析
下一篇: 如何打开ipynb文件