Android Intent的使用

Android中最重要的特征之一就是可以利用一个带有action的intent使当前app能够跳转到其他app。我们必须使用intent来在同一个app的两个activity之间进行切换。通常是定义一个显式(explicit)的intent,它指定了需要启动组件的类名。然而,当想要唤起不同的app来执行某个动作(比如查看地图),则必须使用隐式(implicit)的intent。


1.建立隐式的Intent
隐式并不声明要启动组件的具体类名,而是声明一个需要执行的action。这个action指定了我们想做的事情,例如查看,编辑,发送或者是获取一些东西。Intents通常会在发送action的同时附带一些数据,例如你想要查看的地址或者是你想要发送的邮件信息。数据的具体类型取决于我们想要创建的Intent,比如Uri或其他规定的数据类型,或者甚至也可能根本不需要数据。

  • 拨打电话
Uri number = Uri.parse("tel:111111");
Intent callIntent = new Intent(Intent.ACTION_DIAL, number);
  • 查看地图
// Map point based on address
Uri location = Uri.parse("geo:0,0?q=1600+Amphitheatre+Parkway,+Mountain+View,+California");
// Or map point based on latitude/longitude
// Uri location = Uri.parse("geo:37.422219,-122.08364?z=14"); // z param is zoom level
Intent mapIntent = new Intent(Intent.ACTION_VIEW, location);
  • 查看网页:
Uri webpage = Uri.parse("http://www.android.com");
Intent webIntent = new Intent(Intent.ACTION_VIEW, webpage);

至于另外一些需要extra数据的implicit intent,我们可以使用 putExtra() 方法来添加那些数据。 默认的,系统会根据Uri数据类型来决定需要哪些合适的MIME type。如果我们没有在intent中包含一个Uri, 则通常需要使用 setType() 方法来指定intent附带的数据类型。设置MIME type 是为了指定应该接受这个intent的activity。例如:

  • 发送一个带附件的email:
Intent emailIntent = new Intent(Intent.ACTION_SEND);
// The intent does not have a URI, so declare the "text/plain" MIME type
emailIntent.setType(HTTP.PLAIN_TEXT_TYPE);
emailIntent.putExtra(Intent.EXTRA_EMAIL, new String[] {"[email protected]"}); // recipients
emailIntent.putExtra(Intent.EXTRA_SUBJECT, "Email subject");
emailIntent.putExtra(Intent.EXTRA_TEXT, "Email message text");
emailIntent.putExtra(Intent.EXTRA_STREAM, Uri.parse("content://path/to/email/attachment"));
// You can also attach multiple items by passing an ArrayList of Uris

2.验证是否有App去接收这个Intent
尽管Android系统会确保每一个确定的intent会被系统内置的app(such as the Phone, Email, or Calendar app)之一接收,但是我们还是应该在触发一个intent之前做验证是否有App接受这个intent的步骤。

提示:如果触发了一个intent,而且没有任何一个app会去接收这个intent,则app会crash

为了验证是否有合适的activity会响应这个intent,需要执行queryIntentActivities() 来获取到能够接收这个intent的所有activity的list。若返回的List非空,那么我们才可以安全的使用这个intent。例如:

PackageManager packageManager = getPackageManager();
List<ResolveInfo> activities = packageManager.queryIntentActivities(intent, 0);
boolean isIntentSafe = activities.size() > 0;

如果isIntentSafe为true, 那么至少有一个app可以响应这个intent。false则说明没有app可以handle这个intent。

3.启动Intent完整示例:
下面是一个演示了如何创建一个intent来查看地图的完整例子,首先验证有app可以handle这个intent,然后启动它。

// Build the intent
Uri location = Uri.parse("geo:0,0?q=1600+Amphitheatre+Parkway,+Mountain+View,+California");
Intent mapIntent = new Intent(Intent.ACTION_VIEW, location);

// Verify it resolves
PackageManager packageManager = getPackageManager();
List<ResolveInfo> activities = packageManager.queryIntentActivities(mapIntent, 0);
boolean isIntentSafe = activities.size() > 0;

// Start an activity if it's safe
if (isIntentSafe) {
    startActivity(mapIntent);
}

4.Intent过滤—添加Intent Filter
通过在manifest文件中的标签下添加的属性,使其他的app能够启动我们的activity。
若activity中的intent filter满足以下intent对象的标准,系统就能够把特定的intent发送给activity:

  • Action:一个想要执行的动作的名称。通常是系统已经定义好的值,如ACTION_SEND或ACTION_VIEW。 在intent
    filter中通过指定它的值,值的类型必须为字符串,而不是API中的常量(看下面的例子)
  • Data:Intent附带数据的描述。在intent filter中通过指定它的值,可以使用一个或者多个属性,我们可以只定义MIME type或者是只指定URI prefix,也可以只定义一个URI scheme,或者是他们综合使用。

Note: 如果不想handle Uri 类型的数据,那么应该指定 android:mimeType 属性。例如 text/plain or
image/jpeg.

  • Category:提供一个附加的方法来标识这个activity能够handle的intent。通常与用户的手势或者是启动位置有关。系统有支持几种不同的categories,但是大多数都很少用到。而且,所有的implicit intents都默认是 CATEGORY_DEFAULT 类型的。在intent filter中用指定它的值。

例如,这个有intent filter的activity,当数据类型为文本或图像时会处理ACTION_SEND的intent。

<activity android:name="ShareActivity">
    <intent-filter>
        <action android:name="android.intent.action.SEND"/>
        <category android:name="android.intent.category.DEFAULT"/>
        <data android:mimeType="text/plain"/>
        <data android:mimeType="image/*"/>
    </intent-filter>
</activity>
提示:每一个发送出来的intent只会包含一个action与data类型,但handle这个intent的activity的 <intent-filter>可以声明多个<action>, <category><data>

如果任何的两对action与data是互相矛盾的,就应该创建不同的intent filter来指定特定的action与type。

例如,假设我们的activity可以handle 文本与图片,无论是ACTION_SEND还是ACTION_SENDTO 的intent。在这种情况下,就必须为两个action定义两个不同的intent filter。因为ACTION_SENDTO intent 必须使用 Uri 类型来指定接收者使用 send 或 sendto 的地址。例如:

<activity android:name="ShareActivity">
    <!-- filter for sending text; accepts SENDTO action with sms URI schemes -->
    <intent-filter>
        <action android:name="android.intent.action.SENDTO"/>
        <category android:name="android.intent.category.DEFAULT"/>
        <data android:scheme="sms" />
        <data android:scheme="smsto" />
    </intent-filter>
    <!-- filter for sending text or images; accepts SEND action and text or image data -->
    <intent-filter>
        <action android:name="android.intent.action.SEND"/>
        <category android:name="android.intent.category.DEFAULT"/>
        <data android:mimeType="image/*"/>
        <data android:mimeType="text/plain"/>
    </intent-filter>
</activity>

Note:为了接受implicit intents, 必须在我们的intent filter中包含 CATEGORY_DEFAULT 的category。startActivity()和startActivityForResult()方法将所有intent视为声明了CATEGORY_DEFAULT category。如果没有在的intent filter中声明CATEGORY_DEFAULT,activity将无法对implicit intent做出响应。

5.在Activity中Handle发送过来的Intent
为了决定采用哪个action,我们可以读取Intent的内容。

可以执行getIntent() 来获取启动我们activity的那个intent。我们可以在activity生命周期的任何时候去执行这个方法,但最好是在onCreate()或者onStart()里面去执行。

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    setContentView(R.layout.main);

    // Get the intent that started this activity
    Intent intent = getIntent();
    Uri data = intent.getData();

    // Figure out what to do based on the intent type
    if (intent.getType().indexOf("image/") != -1) {
        // Handle intents with image data ...
    } else if (intent.getType().equals("text/plain")) {
        // Handle intents with text ...
    }
}

6.返回Result

如果想返回一个result给启动的那个activity,仅仅需要执行setResult(),通过指定一个result code与result intent。操作完成之后,用户需要返回到原来的activity,通过执行finish() 关闭被唤起的activity。

 // Create intent to deliver some kind of result data
Intent result = new Intent("com.example.RESULT_ACTION", Uri.parse("content://result_uri");
setResult(Activity.RESULT_OK, result);
finish();

我们必须总是指定一个result code。通常不是RESULT_OK就是RESULT_CANCELED。我们可以通过Intent 来添加需要返回的数据。

Note:默认的result code是RESULT_CANCELED.因此,如果用户在没有完成操作之前点击了back key,那么之前的activity接受到的result code就是”canceled”。

如果只是纯粹想要返回一个int来表示某些返回的result数据之一,则可以设置result code为任何大于0的数值。如果我们返回的result只是一个int,那么连intent都可以不需要返回了,可以调用setResult()然后只传递result code如下:

setResult(RESULT_COLOR_RED);
finish();

Note:我们没有必要在意自己的activity是被用startActivity() 还是
startActivityForResult()方法所叫起的。系统会自动去判断该如何传递result。在不需要的result的case下,result会被自动忽略。

猜你喜欢

转载自blog.csdn.net/ysq_chris/article/details/80929907