必威体育Betway必威体育官网
当前位置:首页 > IT技术

隐式Intent解析

时间:2019-07-20 09:10:00来源:IT技术作者:seo实验室小编阅读:59次「手机版」
 

intent

回顾Android中的隐式intent的相关知识点。

      • 概述
      • 使用
        • action标签
        • category标签
        • data标签
          • mimeType
          • scheme
          • host
          • port
          • path
          • pathPrefix
          • pathPattern
        • data总结
      • 网页启动APP

概述

隐式启动主要解决了界面间的跳转解耦,主要涉及intent-filter中的三个标签:

  • category
  • action
  • data

    它们构成了隐式启动的匹配项,通过不同的配置完成不同的路由跳转。

使用

列一个例子,新建一个APP有两个界面,一为MainActivity,一个为ActionActivityMainActivity中有一个按钮,通过按钮启动隐式Intent来启动ActionActivity

布局和代码非常简单:

MainActivity的布局和代码:

//布局中只有一个按钮
<?xml version="1.0" encoding="utf-8"?>
<Linearlayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <Button
        android:id="@+id/bt_action"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="启动"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</LinearLayout>
//代码
public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedinstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button btn = findViewById(R.id.bt_action);
    }
}

ActionActivity的布局和代码:

//布局中就是一行文字说明
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".ActionActivity">
<TextView
    android:text="我是跳转的页面"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" />
</LinearLayout>
//代码
public class ActionActivity extends AppCompatActivity {

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

action标签

MainActiity的按钮添加代码,如果找不到的话会抛出异常,因此捕获并打印启动失败的信息:

btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
          try{
                //Intent action1 = new Intent("action1");//可以使用构造传入action参数
                Intent action1 = new Intent();
                action1.setAction("action1");
                startActivity(action1);
            }catch (Exception e){
                    toast.maketext(MainActivity.this,"启动失败",Toast.LENGTH_LONG).show();
                    e.printstacktrace();
                }
        });

清单文件中的ActionActivity的配置,可以看到只使用了action标签:

        <activity android:name=".ActionActivity">
            <intent-filter>
                <action android:name="action1"/>
            </intent-filter>
        </activity>

启动MainActivity点击按钮,结果抛出异常:

action跳转

异常结果为:

android.content.ActivitynotfoundException: No Activity found to handle Intent { act=action1 }

所以实际上ActionActivity只配置action标签是不够的。

category标签

增加默认的android.intent.category.DEFAULT

<activity android:name=".ActionActivity">
            <intent-filter>
                <category android:name="android.intent.category.DEFAULT"/>
                <action android:name="action1"/>
            </intent-filter>
        </activity>

intent的代码不做变动,这时点击按钮可以正常跳转:

action跳转

说明这里category 是必须要配置的,Intent虽然没有设置category,但是默认就是这个android.intent.category.DEFAULT,所以能够匹配到。

再增加一个action试试:

        <activity android:name=".ActionActivity">
            <intent-filter>
                <category android:name="android.intent.category.DEFAULT"/>
                <action android:name="action1"/>
                <action android:name="action2"/>
            </intent-filter>
        </activity>

intent的代码不做变动,点击按钮依旧可以正常跳转,效果不再贴出。

如果给Intent增加一个intent-filter标签中没有的action试试:

 Intent action1 = new Intent();
                action1.setAction("action1");
                action1.setAction("action3");
                startActivity(action1);

点击抛出ActivityNotFoundException异常,,效果不再贴出。

通过上面的测试说明intent设置的action必须为目标页面intent-filteraction的子集才能正常跳转,并且是区分大小写的。

测试完了action,更换下category为自定义的category1试试:

<activity android:name=".ActionActivity">
            <intent-filter>
                <category android:name="category1"/>
                <action android:name="action1"/>
            </intent-filter>
        </activity>

代码中:

                Intent action1 = new Intent();
                action1.setAction("action1");
                action1.addCategory("category1");
                startActivity(action1);

运行点击抛出ActivityNotFoundException异常,效果不再贴出。

然后增加android.intent.category.DEFAULT这个默认的action在测试:

         <activity android:name=".ActionActivity">
            <intent-filter>
                <category android:name="android.intent.category.DEFAULT"/>
                <category android:name="category1"/>
                <action android:name="action1"/>
            </intent-filter>
        </activity>

运行点击按钮可以正常跳转,效果不再贴出。

说明android.intent.category.DEFAULT这个默认的action是必须要在intent-filter标签中声明的。

如果存在多个action匹配的页面,那么启动后会弹出选择对话框,比如编写一个新的界面为Action2Activity,它也接受action1的动作:

布局:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".Action2Activity">
    <TextView
        android:text="我也是跳转的页面!"
        android:textSize="32dp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
</LinearLayout>

清单文件:

 <activity android:name=".Action2Activity">
            <intent-filter>
                <category android:name="android.intent.category.DEFAULT" />
                <action android:name="action1" />
            </intent-filter>
        </activity>

代码只设置action1

                    Intent action1 = new Intent();
                    action1.setAction("action1");
                    startActivity(action1);

运行效果:

多页面匹配

如果再增加一个自定义的category2试试:

 <activity android:name=".ActionActivity">
            <intent-filter>
                <category android:name="android.intent.category.DEFAULT"/>
                <category android:name="category1"/>
                <category android:name="category2"/>
                <action android:name="action1" />
            </intent-filter>
        </activity>

代码不做变动,点击按钮可以正常跳转。

如果在代码中增加一个category3试试:

 Intent action1 = new Intent();
                action1.addCategory("category1");
                action1.addCategory("category3");
                action1.setAction("action1");
                startActivity(action1);

运行点击抛出ActivityNotFoundException异常,效果不再贴出。

同样说明intent中的category,必须为目标页面intent-filtercategory的子集才能正常跳转,和action的匹配规则是一样的。

另外说明下,只使用category而不添加任何action也是无法匹配的,说明intent中的action是必须要设置的。而且如果配置了多个intent-filter标签也是按照一组一组进行匹配的,直到与其中一组匹配成功。

data标签

data标签自然不是必须的,主要为URL的表现形式,它的格式如下:

                <data android:mimeType=""/>//媒体类型 例如 "image/*"就是匹配图片类型
                <data android:scheme=""/>//例如: http,https
                <data android:host=""/>//例如:www.csdn.net
                <data android:port=""/>//例如:8080
                <data android:path=""/> // 路径:如 /nav/blockchain
                <data android:pathPrefix=""/>
                <data android:pathPattern=""/>// 正则表达式标识的路径
                <data android:ssp=""/>
                <data android:sspPrefix=""/>
                <data android:sspPattern=""/>

data的属性比较多:

  • mimeType 媒体类型 例如 image/*就是匹配图片类型,mimeType类型比较多 ,这里不再列出;
  • scheme类似如 http,https
  • host类似www.csnd.com
  • port类似 8080
  • path 路径:/nav/blockchain
  • pathPrefix 路径前缀:/nav
  • pathPattern 路径的正则表达式方式
  • ssp //可以匹配系统特定intent 相关文章通过android:ssp高效过滤Android Intents
  • sspPrefix//可以匹配系统特定intent
  • sspPattern//可以匹配系统特定intent

    类似这样<scheme>://<host>:<port>[<path>|<pathPrefix>|<pathPattern>]

    例如action://action1:44/abc/xyz

mimeType

改动下上面的例子:

        <activity android:name=".ActionActivity">
            <intent-filter>
                <category android:name="android.intent.category.DEFAULT"/>
                <action android:name="action1"/>
                <data android:mimeType="image/*"/>//指定媒体类型为图片的类型
            </intent-filter>
        </activity>

代码中不设置action,只设置mimeType

                    Intent action1 = new Intent();
                    action1.setType("image/png");//指定了媒体类型为png的图片类型
                    startActivity(action1);

运行效果:

mimeType跳转

这里可以看到只要有任何能够匹配的mimeTypeimage/png的应用都会在底部的列表弹出,但是如果Intent不设置mimeType而只设置action,那么是无法匹配的,说明mimeType的需要优先匹配的。

如果actionmimeType完全匹配,就可以更为精准的匹配。

需要注意的是清单文件中设置了mimeType而不设置scheme的话,intent中的默认的schemecontent或者file才能进行匹配(在API 24以后只能对应contentscheme了),意味着mimeType其实对应了默认的scheme

看下代码实现:

                    Intent action1 = new Intent();
                    action1.setDataAndType(Uri.parse("content://action1"),"image/png");
                    action1.setAction("action1");
                    startActivity(action1);

这里setDataAndType方法才能同时设置datamimeType,单独使用setData或者setType两者都会将对方清空。

同样如果清单文件中指定了多个mimeType那么,只要Intent匹配到一个就可以。

scheme

在上面的例子中scheme就是content://action1中的content了,更改个自定义的scheme测试:

 <activity android:name=".ActionActivity">
            <intent-filter>
                <category android:name="android.intent.category.DEFAULT" />
                <action android:name="action1" />
                <data android:mimeType="image/*"/>
                <data android:scheme="action"/>
            </intent-filter>
        </activity>
 Intent action1 = new Intent();
  action1.setDataAndType(Uri.parse("action://action1"),"image/png");
  action1.setAction("action1");
  startActivity(action1);

运行可以正常启动的,这里不再帖效果。当然清单文件不设置mimeType的话,Intent就可以使用setData方法来设置URL的。

host

上面例子的action://action1action1就是host了,需要注意的是如果清单文件中没有指定host的话, portpathpathPrefixpathPattern都不会生效。

port

port需要和host放在同一个data标签内才能生效:

 <activity android:name=".ActionActivity">
            <intent-filter>
                <category android:name="android.intent.category.DEFAULT" />
                <action android:name="action1" />
                <data android:scheme="action"/>
                <data android:host="action1" android:port="44"/>
                <data />
            </intent-filter>
        </activity>

代码:

 Intent action1 = new Intent();
 action1.setData(Uri.parse("action://action1:44"));
 action1.setAction("action1");
 startActivity(action1);

可以正常跳转。

path

代码增加/abc/xyz

 Intent action1 = new Intent();
 action1.setData(Uri.parse("action://action1:44/abc/xyz"));
 action1.setAction("action1");
 startActivity(action1);

清单文件:

 <activity android:name=".ActionActivity">
            <intent-filter>
                <category android:name="android.intent.category.DEFAULT" />
                <action android:name="action1" />
                <data android:scheme="action"/>
                <data android:host="action1" android:port="44"/>
                <data android:path="/abc/xyz"/>//必须以/开头
                <data />
            </intent-filter>
        </activity>

这样完全匹配。

pathPrefix

匹配path的前缀,上面例子中就是/abc

 <activity android:name=".ActionActivity">
            <intent-filter>
                <category android:name="android.intent.category.DEFAULT" />
                <action android:name="action1" />
                <data android:scheme="action"/>
                <data android:host="action1" android:port="44"/>
                <data android:pathPrefix="/abc"/>
                <data />
            </intent-filter>
        </activity>
pathPattern

利用正则表达式/.*匹配/abc:

 <activity android:name=".ActionActivity">
            <intent-filter>
                <category android:name="android.intent.category.DEFAULT" />
                <action android:name="action1" />
                <data android:scheme="action"/>
                <data android:host="action1" android:port="44"/>
                <data android:pathPattern="/.*/xyz"/>
            </intent-filter>
        </activity>

.*就是表示匹配任意字符,这样也能够灵活匹配,需要注意正则表达式中的符号如果当做字符处理需要进行转义。

data总结

比如要匹配action://action1:44/abc/xyz这样的URL的话,清单文件中至少需要写到scheme:

   <data android:scheme="action"/>

其实也就是说Intent中的data应该为清单文件中data的子集。

从网页启动app

隐式Intent也可以从网页中启动Activity,比如有一个远程网页内容如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<a href="action://action1:44/abc/xyz?m=1&n=2">启动页面</a>
</body>
</html>

a标签中的href为自定义链接,对应的在清单文件中做出改动:

        <activity android:name=".ActionActivity">
            <intent-filter>
                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="android.intent.category.BROWSABLE" />
                <action android:name="android.intent.action.VIEW" />
                <data
                    android:scheme="action"
                    android:host="action1"
                    android:port="44"
                    android:path="/abc/xyz"
                   />
            </intent-filter>
        </activity>

ActionActivity中可以获取各种数据

public class ActionActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_action);
        Uri data = getIntent().getData();
        if (data != null){
            Log.d("url",data.toString());
            String scheme = data.getScheme();
            Log.e("scheme", scheme);
            String host = data.getHost();
            Log.e("host", host);
            int port = data.getPort();
            Log.e("port", port+"");
            String path = data.getPath();
            Log.e("path", path);
            List<String> pathsegments = data.getPathSegments();//路径分割
            String params = data.getQuery();
            Log.e("params", params);
            String value = data.getQueryparameter("m");
            Log.e("m值", value);
        }
    }
}

如果从浏览器中打开页面,点击a标签链接,可以成功跳转并看到打印结果:

网页跳转APP

08-20 11:33:01.181 4491-4491/cn.franky.test E/scheme: action
08-20 11:33:01.182 4491-4491/cn.franky.test E/host: action1
08-20 11:33:01.182 4491-4491/cn.franky.test E/port: 44
08-20 11:33:01.182 4491-4491/cn.franky.test E/path: /abc/xyz
08-20 11:33:01.182 4491-4491/cn.franky.test E/params: m=1&n=2
08-20 11:33:01.182 4491-4491/cn.franky.test E/m值: 1

隐式Intent总结到此。

相关阅读

淘宝玩小游戏赢金币,具体操作步骤解析!

淘宝玩小游戏赢金币可能很多朋友之前都已经玩过了,就和我们平时玩的小游戏一样,只要好的一点,这些游戏的奖励是淘宝淘金币,可以在购买

最详细的动态评分计算方法(附DSR计算公式解析)

大家知道,淘宝店铺动态评分不仅影响着一个店铺的搜索排名情况,而且还会直接影响消费者购买欲望,如果评分太差,那还有客户敢购买吗?所

支付宝海外购物在哪里?支付宝海外购常见问题解析

近几年随着进口产品越来越收欢迎,很多朋友都倾向于购买海外产品,那么作为最大的网络支付平台支付宝是否可以支持海外购物呢?支付宝

大数据平台-元数据管理系统解析

什么是元数据?在前面的集成开发环境建设相关文章中,我们也提到过,元数据MetaData狭义的解释是用来描述数据的数据,广义的来看,除了业务

电影《不能说的秘密》完全解析更新

周杰伦 自导自演自编的 《不能说的秘密》 真的是太好看了 国产中绝对的佳作n(≧▽≦)n 顺带:周杰伦好多歌曲真好听啊OvO,好听的

分享到:

栏目导航

推荐阅读

热门阅读