Android Intent(意图)介绍

对于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。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值