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()方法来设置。

扫描二维码关注公众号,回复: 1904337 查看本文章
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://stackoverflow.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()

猜你喜欢

转载自blog.csdn.net/sinat_34383316/article/details/76039483