欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Android Intent(意图)介绍

程序员文章站 2022-05-28 14:48:04
...

对于Android Intent大家肯定不陌生,Intent顾名思义就是“意图”的意思。其实这个“意图”有点不好理解。其实简单点就是我想要“干什么”。你比如说,我想要“去火车站”、我想要“启动一个Activity”、我想要“启动一个server”、我想要XXX都是意图。Intent有显式Intent和隐式Intent两种情况。


那么问题来了:

一.那到底什么样的Intent是显式的Intent,什么样的Intent是隐式的Intent呢?

为了回答这个问题,请看下面对于隐式Intent和显式Intent的具体介绍


1 隐式Intent

说起隐式Intent就不得不先说在清单文件(AndroidManifest.xml)中的intent-filter。你随便创建一个Android 项目都会在清单文件中看见intent-filter,顾名思义就是Intent的过滤器。而且一个Activity组件的声明中,可以有多个intent-filter。当然也可以没有intent-filter。


举个例子如下:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.mytest">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <!--1个intent-filter-->
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <!--没有intent-filter-->
        <activity android:name=".Main2Activity" />

        <!--多个intent-filter-->
        <activity android:name=".Main3Activity">
            <intent-filter>
                <action android:name="com.mytest.MyIntentAction" />

                <category android:name="android.intent.category.DEFAULT" />

                <data android:mimeType="aa/bb"/>
            </intent-filter>
            <intent-filter>
                <action android:name="com.mytest.MyIntentAction1" />

                <category android:name="android.intent.category.DEFAULT" />

                <data android:scheme="myIntent1" android:host="8080"/>
            </intent-filter>
            <intent-filter>
                <action android:name="com.mytest.MyIntentAction2" />

                <category android:name="android.intent.category.DEFAULT" />

                <data android:scheme="myIntent2"/>
            </intent-filter>
        </activity>
    </application>

</manifest>

intent-filter实行“白名单”管理,即只列出组件乐意接受的Intent,但intent-filter只会过滤隐式Intent,显式的Intent会直接传送到目标组件。 Android组件可以有一个或多个intent-filter,每个intent-filter之间相互独立,只需要其中一个intent-filter中的所有过滤条件条件(Action、Data、Category)全部被满足则验证通过。就说明该Intent是可以启动该Activity的。除了用于过滤广播的intent-filter可以在代码中创建外,其他的intent-filter必须在AndroidManifest.xml文件中进行声明。

intent-filter中具有和Intent对应的用于过滤Action,Data和Category的字段,一个隐式Intent要想被一个组件处理,必须匹配这三个(Action,Data和Category字段。下面具体介绍一下这三个字段

1.1 Action
检查 Action 尽管一个Intent只可以设置一个Action,但一个Intentfilter可以持有一个或多个Action用于过滤,到达的Intent只需要匹配其中一个Action即可。 深入思考:如果一个Intentfilter没有设置Action的值,那么,任何一个Intent都不会被通过;反之,如果一个Intent对象没有设置Action值,那么它能通过所有的Intent-filter的Action检查。

1.2 Data
检查 Data 同Action一样,Intent-filter中的Data部分也可以是一个或者多个,而且可以没有。每个Data包含的内容为URL和数据类型,进行Data检查时主要也是对这两点进行比较,比较规则: 如果一个Intent对象没有设置Data,只有Intent-filter中也没有设置Data时才可通过检查。 如果一个Intent对象包含URI,但不包含数据类型:仅当Intent-filter也不指定数据类型,同时它们的URI匹配,才能通过检测。 如果一个Intent对象包含数据类型,但不包含URI:仅当Intentfilter也没指定URL,而只包含数据类型且与Intent相同,才通过检测。 如果一个Intent对象既包含URI,也包含数据类型(或数据类型能够从URI推断出),只有当其数据类型匹配Intent-filter中的数据类型,并且通过了URL检查时,该Intent对象才能通过检查。
其中URL由四部分组成:它有四个属性scheme、host、port、path对应于URI的每个部分。
例如:content://com.wjr.example1:121/files
       scheme部分:content
       host部分:com.wjr.example1
       port部分:121
       path部分:files

host和port部分一起构成URI的凭据(authority),如果host没有指定,那port也会被忽略。
这四个属性是可选的,但他们之间并不是完全独立的。要让authority有意义,scheme必须要指定。要让path有意思,scheme和authority必须指定。Intent-filter中的path可以使用通配符来匹配path字段,Intent和Intent-filter都可以用通配符来指定MIME类型。

1.3Category
检查 CategoryIntent-filter中可以设置多个Category,Intent中也可以含有多个Category,只有Intent中的所有Category都能匹配到Intentfilter中的Category,Intent才能通过检查。也就是说,如果Intent中的Category集合是Intent-filter中Category的集合的子集时,Intent才能通过检查。如果Intent中没有设置Category,则它能通过所有Intent-filter的Category检查。 如果一个Intent能够通过不止一个组件的Intent-filter,用户可能会被问哪个组件被**。如果没有目标找到,会产生一个异常。

Intent-filter
应用程序的组件为了告诉Android自己能响应、处理哪些隐式Intent请求,可以声明一个甚至多个IntentFilter。每个 IntentFilter描述该组件所能响应Intent请求的能力——组件希望接收什么类型的请求行为,什么类型的请求数据。比如之前请求网页浏览器这 个例子中,网页浏览器程序的IntentFilter就应该声明它所希望接收的Intent Action是WEB_SEARCH_ACTION,以及与之相关的请求数据是网页地址URI格式。
如何为组件声明自己的IntentFilter? 常见的方法是在AndroidManifest.xml文件中用属性描述组件的IntentFilter。
前面我们提到,隐式Intent和IntentFilter进行比较时的三要素是Intent的Action、Data以及Category。实际上,一个隐式Intent请求要能够传递给目标组件,必要通过这三个方面的检查。如果任何一方面不匹配,Android都不会将该隐式Intent传递给目标组件。


讲完了AndroidManifest.xml中的Intent-filter.就要看一下如何在代码中一个隐式的Intent,去启动一个组件。下面我们来看一个代码例子,我创建了一个Android 项目,除了默认的MainActivity我又增加了两个Activity:Main2Activity、Main3Activity。


其中Main2Activity由MainActivity启动,暂时不看启动Main2Activity的代码,现在我们先看Main2Activity中使用隐式的Intent启动Main3Activity的代码。根据AndroidManifest.xml中Main3Activity的声明来看,有三个intent-filter可以启动Main3Activity,所以我随机选一个intent-filter进行Intent的设置就可以了。我选用第三个intent-filter来启Main3Activity。

            <intent-filter>
                <action android:name="com.mytest.MyIntentAction2" />

                <category android:name="android.intent.category.DEFAULT" />

                <data android:scheme="myIntent2"/>
            </intent-filter>

AndroidManifest.xml中的action中的内容和Data中的内容都是我随便写的,因为在android默认的那些action和data的数据中也是一个字符串,所以我们可以设置其为任意字符串。根据这个intent-filter我在Main2Activity.java中的代码实现如下:

package com.mytest;

import android.content.Intent;
import android.net.Uri;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

public class Main2Activity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main2);

        //创建隐式Intent
        Intent intent = new Intent();

        //为隐式Intent添加过滤Action,Data和Category的字段,
        // 不是说必须这三个字段同时有,这个设置那些是根据清单文件中Main3Activity的某一个intent-filter确定的
        intent.setAction("com.mytest.MyIntentAction2");
        intent.addCategory("android.intent.category.DEFAULT");
        intent.setData(Uri.parse("myIntent2:" + 110));//后边的110是随便加的,暂时没有什么具体的意思,这就是他的一个用法

        //启动Main3Activity
        startActivity(intent);
    }
}

这就是使用隐式的Intent启动组件。


2 显式Intent

其实显式Intent就很简单了,我们直接来看代码。我在MainActivity.java中使用显式Intent启动Main2Activity,代码如下

package com.mytest;

import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //创建显示Intent
        Intent intent = new Intent(getApplicationContext(),com.mytest.Main2Activity.class);

        //启动Activity
        startActivity(intent);
    }
}

这就是显式的Intent去启动组件。


总的一句话,如果创建Intent的时候,明确指出了要启动的class的名字,就是显示Intent。如果没有明确的指出要启动的class的名,而是通过设置intent的过滤字段启动class,就是隐式Intent.


二.什么时候用显示Intent,什么时候用隐式Itent呢?

一句话:当你启动自己写的同一个APP中的Activity时使用显示Intent,当你要启动其他人写APP中的Activity时使用隐式Intent。