安卓Activity隐式启动全面解析

前言

安卓有两种方式启动Activity,一种是显示启动,另外一种是隐式启动。显示启动我们在项目中经常用到,大家也都比较熟悉。今天我们主要讲解一下隐式启动。隐式启动常用于不同应用之间的跳转(例如打开支付宝微信的支付页面),也可用于H5与native之间的交互。隐式启动就是action,category和data的匹配,我们先来说下匹配的规则,然后通过具体的例子去验证。

匹配规则

  1. action的匹配规则
  • action在Intent-filter可以设置多条
  • intent中必须指定action否则匹配失败且intent中action最多只有一条
  • intent中的action和intent-filter中的action必须完全一样时(包括大小写)才算匹配成功
  • intent中的action只要与intent-filter其中的一条匹配成功即可
<activity android:name=".MainActivity">
    <intent-filter>
        <action android:name="android.intent.action.MAIN"/>
        <category android:name="android.intent.category.LAUNCHER"/>
    </intent-filter>

    <intent-filter>
        <action android:name="com.jrmf360.action.ENTER"/>
        <action android:name="com.jrmf360.action.ENTER2"/>
        <category android:name="android.intent.category.DEFAULT"/>
    </intent-filter>
</activity>

下面的两个intent都可以匹配上面MainActivity的action规则

Intent intent = new Intent("com.jrmf360.action.ENTER");
startActivity(intent);

Intent intent2 = new Intent("com.jrmf360.action.ENTER2");
startActivity(intent2);
  1. category的匹配规则
  • category在intent-filter中可以有多条
  • category在intent中也可以有多条
  • intent中所有的category都可以在intent-filter中找到一样的(包括大小写)才算匹配成功
  • 通过intent启动Activity的时候如果没有添加category会自动添加android.intent.category.DEFAULT,如果intent-filter中没有添加android.intent.category.DEFAULT则会匹配失败
  1. data的匹配规则
    在说data的匹配规则之前我们先来说说data的语法
<data 
  android:host="string"
  android:mimeType="string"
  android:path="string"
  android:pathPattern="string"
  android:pathPrefix="string"
  android:port="string"
  android:scheme="string"/>

举个栗子

scheme://host:port/path|pathPrefix|pathPattern
jrmf://jrmf360.com:8888/first

scheme:主机的协议部分,如jrmf
host:主机部分,如jrmf360.com
port: 端口号,如8888
path:路径,如first
pathPrefix:指定了部分路径,它会跟Intent对象中的路径初始部分匹配,如first
pathPattern:指定的路径可以进行正则匹配,如first
mimeType:处理的数据类型,如image/*

  • intent-filter中可以设置多个data
  • intent中只能设置一个data
  • intent-filter中指定了data,intent中就要指定其中的一个data
  • setType会覆盖setData,setData会覆盖setType,因此需要使用setDataAndType方法来设置data和mimeType

实例验证

新建两个项目externalstart1和externalstart2,在externalstart1中添加几个button,点击button通过隐式启动打开externalstart2中的Activity
先来看看externalstart2中隐式启动的配置

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

    <intent-filter>
        <action android:name="com.jrmf360.action.ENTER"/>
        <category android:name="android.intent.category.DEFAULT"/>
        <data
            android:host="jrmf360.com"
            android:port="8888"
            android:scheme="jrmf"/>
    </intent-filter>
</activity>

<activity android:name=".FirstActivity">
</activity>

<activity android:name=".SecondActivity">
</activity>

在externalstart2项目中共有三个Activity,分别为MainActivity,FirstActivity和SecondActivity。externalstart1项目通过隐式启动跳转到MainActivity,在MainActivity中通过隐式启动传递的路径(path)来打开FirstActivity或者SecondActivity。MainActivity的代码如下:

public class MainActivity extends AppCompatActivity {

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

    private void parseData() {
        Uri data = getIntent().getData();
        if (data != null){
            String scheme = data.getScheme();
            String host = data.getHost();
            int port = data.getPort();
            String path = data.getPath();
            String query = data.getQuery();
            String message = data.getQueryParameter("message");
            Log.e(getClass().getSimpleName(),"scheme:"+scheme);
            Log.e(getClass().getSimpleName(),"host:"+host);
            Log.e(getClass().getSimpleName(),"port:"+port);
            Log.e(getClass().getSimpleName(),"path:"+path);
            Log.e(getClass().getSimpleName(),"query:"+query);

            if ("/first".equals(path)){
                FirstActivity.intent(this,message);
                finish();
            }else if ("/second".equals(path)){
                SecondActivity.intent(this,message);
                finish();
            }
        }
    }
}

当path为first时跳转到FirstActivity,path为second时跳转到SecondActivity,并打印data的各个部分日志;
在externalstart1中通过点击按钮来跳转到externalstart2项目中,下面看下externalstart1中按钮的点击逻辑:

@Override
public void onClick(View v) {
    int id = v.getId();
    if (id == R.id.btn_firstActivity){
        Intent intent = new Intent();
        intent.setAction("com.jrmf360.action.ENTER");
        intent.setData(Uri.parse("jrmf://jrmf360.com:8888/first?message=Hello FirstActivity"));
        startActivity(intent);

    }else if (id == R.id.btn_secondActivity){
        Intent intent = new Intent();
        intent.setAction("com.jrmf360.action.ENTER");
        intent.setData(Uri.parse("jrmf://jrmf360.com:8888/second?message=Hello SecondActivity"));
        startActivity(intent);
    }else if (id == R.id.btn_mainActivity){
        Intent intent = new Intent("com.jrmf360.action.ENTER");
        intent.setData(Uri.parse("jrmf://jrmf360.com:8888"));
        startActivity(intent);
    }
}

根据按钮的名字很容易看出各个按钮需要跳转到的Activity。
下面做点击测试:

  • 点击btn_mainActivity
    会跳转到MainActivity,我们就看下打印的日志,就不贴页面了
07-27 17:38:14.224 6568-6568/com.jrmf360.externalstart2 E/MainActivity: scheme:jrmf
07-27 17:38:14.224 6568-6568/com.jrmf360.externalstart2 E/MainActivity: host:jrmf360.com
07-27 17:38:14.224 6568-6568/com.jrmf360.externalstart2 E/MainActivity: port:8888
07-27 17:38:14.224 6568-6568/com.jrmf360.externalstart2 E/MainActivity: path:/
07-27 17:38:14.224 6568-6568/com.jrmf360.externalstart2 E/MainActivity: query:null

可以看到path和query都为空

  • 点击btn_firstActivity
    会先跳转到MainActivity页面然后根据传递的path再打开FirstActivity,看下日志
07-27 17:39:49.145 6568-6568/com.jrmf360.externalstart2 E/MainActivity: scheme:jrmf
07-27 17:39:49.145 6568-6568/com.jrmf360.externalstart2 E/MainActivity: host:jrmf360.com
07-27 17:39:49.145 6568-6568/com.jrmf360.externalstart2 E/MainActivity: port:8888
07-27 17:39:49.145 6568-6568/com.jrmf360.externalstart2 E/MainActivity: path:/first
07-27 17:39:49.145 6568-6568/com.jrmf360.externalstart2 E/MainActivity: query:message=Hello FirstActivity

从日志中看到path为First,query为message=Hello FirstActivity,因此会打开FirstActivity并把message Hello FirstActivity传递过去。

  • 点击btn_secondActivity
    会先跳转到MainActivity页面然后根据传递的path再打开SecondActivity,看下日志:
07-27 17:41:56.712 6568-6568/com.jrmf360.externalstart2 E/MainActivity: scheme:jrmf
07-27 17:41:56.712 6568-6568/com.jrmf360.externalstart2 E/MainActivity: host:jrmf360.com
07-27 17:41:56.712 6568-6568/com.jrmf360.externalstart2 E/MainActivity: port:8888
07-27 17:41:56.712 6568-6568/com.jrmf360.externalstart2 E/MainActivity: path:/second
07-27 17:41:56.712 6568-6568/com.jrmf360.externalstart2 E/MainActivity: query:message=Hello SecondActivity
07

从日志中看到path为second,query为message=Hello SecondActivity,因此会打开SecondActivity并把message Hello SecondActivity传递过去。

其它事项

  1. android.intent.action.MAIN :程序最先启动的Activity可以给多个Activity设置
  2. android.intent.category.LAUNCHER:应用程序是否显示在桌面,可以给多个Activity配置
  3. android.intent.action.MAIN和android.intent.category.LAUNCHER同时设置会在launcher显示一个应用图标,单独设置android.intent.category.LAUNCHER不会出现图标,且一个应用程序最少要有一对。也可以设置多对,这样会在系统桌面出现过个应用程序图标。

隐式启动的知识点就讲完了,更多应用新姿势等待您的挖掘。

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • Android 的活动是可以包含用户界面的组件,主要用于与用户进行交互。 1 手动创建活动 手动创建活动可以加深对...
    deniro阅读 3,696评论 0 10
  • 前言 我们在开发一个app时,最常用到的是通过Intent设置组件类名,然后启动相应的Activity。这种通过为...
    健忘仙森阅读 3,960评论 0 3
  • 1. 什么是Activity Activity负责UI元素的加载与页面之前的跳转,代表了一个页面单元。 2. Ac...
    付凯强阅读 529评论 0 0
  • Intent组件虽然不是四大组件,但却是连接四大组件的桥梁,学习好这个知识,也非常的重要。 一、什么是Intent...
    困惑困惑困惑阅读 1,540评论 0 0
  • 不知道从什么时候开始,还是一直是这样,行动力总是间歇性降为零,畏难,慵懒,随性。不到最后关头,不采取行动,得过且过...
    延小狼阅读 178评论 0 3