zoukankan      html  css  js  c++  java
  • Android Intent 和 Intent 过滤器

    Android Intent 和 Intent 过滤器

    来源 https://zhuanlan.zhihu.com/p/45397580

    参考 https://juejin.im/entry/575fd1452e958a0058f44b8b

    参考 https://blog.csdn.net/cnnumen/article/details/8464786

    关于启动模式的话,后面我们专门针对Android艺术探索那本书上的个章节做一个总结。可以先看看Intent Filter, 基本上我们刚开始或者已经做了一些项目都有可能还用不到这个(也不能说用不到,就是说没专门自己去定义过),可能还不知道这个有什么用处,如何使用;只知道我们需要一些什么定义就去网上查,基本就是摸着石头过河....

    石头摸够了,小白的我们可以来多看一些这方面的知识,拓展自己的认知和深度...

    官方中文文档: Intent 和 Intent 过滤器

    Intent简介
    Android中提供了Intent机制来协助应用间的交互与通讯,Intent负责对应用中一次操作的动作、动作涉及数据、附加数据进行描述,Android则根据此Intent的描述,负责找到对应的组件,将 Intent传递给调用的组件,并完成组件的调用。Intent不仅可用于应用程序之间,也可用于应用程序内部的Activity/Service之间的交互。因此,Intent在这里起着一个媒体中介的作用,专门提供组件互相调用的相关信息,实现调用者与被调用者之间的解耦。在SDK中给出了Intent作用的表现形式为:
    
    
    通过Context.startActivity() orActivity.startActivityForResult() 
    启动一个Activity;
    通过 Context.startService() 启动一个服务,或者通过Context.bindService() 和后台服务交互;
    通过广播方法(比如 Context.sendBroadcast(),Context.sendOrderedBroadcast(),  
    Context.sendStickyBroadcast()) 发给broadcast receivers。
    
    ntent可分为隐式(implicitly)和显式(explicitly)两种:
    
    
    (1)显式 Intent
    
           即在构造Intent对象时就指定接收者,它一般用在知道目标组件名称的前提下,一般是在相同的应用程序内部实现的,如下:
    
    Intent intent = new Intent(MainActivit.this, NewActivity.class);
    startActivity(intent );  12
    
    上面那个intent中,直接指明了接收者:NewActivity
    
    (2)隐式 Intent
    
           即Intent的发送者在构造Intent对象时,并不知道也不关心接收者是谁,有利于降低发送者和接收者之间的耦合,它一般用在没有明确指出目标组件名称的前提下,一般是用于在不同应用程序之间,如下:
    
    
    
    Intent intent = new Intent();
    intent.setAction("com.wooyun.test");
    startActivity(intent);123
    
           上面那个intent,没有指明接收者,只是给了一个action作为接收者的过滤条件。 
           对于显式Intent,Android不需要去做解析,因为目标组件已经很明确,Android需要解析的是那些隐式Intent,通过解析,将Intent映射给可以处理此Intent的Activity、IntentReceiver或Service。
    
    ---------------------
    
    本文来自 猴子搬来的救兵Castiel 的CSDN 博客 ,全文地址请点击:https://blog.csdn.net/mynameishuangshuai/article/details/51673273?utm_source=copy 

    官方的隐式调用特殊说明:

         为了确保应用的安全性,启动 Service 时,请始终使用显式 Intent,且不要为服务声明 Intent 过滤器。
    使用隐式 Intent 启动服务存在安全隐患,因为您无法确定哪些服务将响应 Intent,且用户无法看到哪些服务已启动。
    从 Android 5.0(API 级别 21)开始,如果使用隐式 Intent 调用 bindService(),系统会引发异常

    一、action的匹配规则

    1. 隐式Intent的情况下,我们只能通过匹配规则找到对应想要唤起的页面,包括第三方应用的页面...比如给某个页面定义一个action..

         <!--页面IntentFilterTestActvity2-->
            <activity android:name="com.example.IntentFilterTestActvity2">
                <intent-filter>
                    <action android:name="nishisbma?"/>
                    <category android:name="android.intent.category.DEFAULT"/>
                </intent-filter>
            </activity>

    注意:<category android:name="android.intent.category.DEFAULT"/>必须要!

    每一个通过 startActivity() 方法发出的隐式 Intent 都至少有一个 category,
    就是 “android.intent.category.DEFAULT”,所有只要是想接收一个隐式 Intent 的 Activity 
    都应该包括 “android.intent.category.DEFAULT” category,不然将导致 Intent 匹配失败,
    然后崩溃,找不到activity...

    来自官方解释:

    2. 系统也提供了一些公用页面供我们使用,比如说发短信,打电话,网页搜索等(具体需要携带的参数可以查相关资料)

            ///< 发短信
            Uri sms_uri= Uri.parse("smsto:13517596490");
            Intent intent = new Intent(Intent.ACTION_SENDTO, sms_uri) ;
    
            ///< 搜索
            Intent intent2 = new Intent(Intent.ACTION_WEB_SEARCH);
            //intent2.putExtra(SearchManager.QUERY,"sb");
    
            startActivity(intent2);

    为了避免崩溃,我们需要做一下判断:

    // Verify the original intent will resolve to at least one activity
    if (sendIntent.resolveActivity(getPackageManager()) != null) {
        startActivity(chooser);
    }

    这样防止匹配不到而导致崩溃...

            ///< 发短信
            Uri sms_uri= Uri.parse("smsto:13517596490");
            Intent intent = new Intent(Intent.ACTION_SENDTO) ;
            if (intent.resolveActivity(getPackageManager()) == null) {
                Toast.makeText(this, "空啦,你个sb,没sms_uri", Toast.LENGTH_SHORT).show();
            }

    3. 暂时这样,后面有情况再补上

     

    二、data的匹配规则 (不迷糊,看官方说明,顺便回顾下) - 主要的目的就是声明接收或者说接受的数据类型

      每个 Intent 过滤器均由应用清单文件中的 <intent-filter> 元素定义,并嵌套在相应的应用组件(例如,<activity> 元素)中。 在 <intent-filter> 内部,您可以使用以下三个元素中的一个或多个指定要接受的 Intent 类型:
    
    <action>
    在 name 属性中,声明接受的 Intent 操作。该值必须是操作的文本字符串值,而不是类常量。
    <data>
    使用一个或多个指定数据 URI 各个方面(scheme、host、port、path 等)和 MIME 类型的属性,声明接受的数据类型。
    <category>
    在 name 属性中,声明接受的 Intent 类别。该值必须是操作的文本字符串值,而不是类常量。

    1. 怎么解释呢?

    比如说有时候你点击.mp3文件选择打开方式的时候是不是可以选择手机上所有可以播放音乐的软件?再比如分享一个本地文件的时候是不是可以选择短信,qq, 微信,skype等软件? 打开文档的时候是不是可以选择qq,wps,html查看器?

    2. 由MineType和URI组成

         minetype: 列如imgage/jpeg,auto/mpeg4和viedo/*等,可以表示图片、文本、视频等不同的媒体格式 
         uri:      则由scheme、host、port、path | pathPattern | pathPrefix这4部分组成

    先看minetype:

       <activity android:name="com.example.IntentFilterTestActivity">
                <intent-filter android:scheme="http"
                    tools:ignore="AppLinkUrlError">
                    <action android:name="android.intent.action.VIEW" />
                    <category android:name="android.intent.category.DEFAULT" />
                    <data android:mimeType="audio/*" />
                </intent-filter>
            </activity>

    这样当我去打开一个音频的时候会发现我的应用也出现再打开应用列表中了..

    3. 来自官方的社交的配置:

        <activity android:name="MainActivity">
        <!-- This activity is the main entry, should appear in app launcher -->
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
    
    <activity android:name="ShareActivity">
        <!-- This activity handles "SEND" actions with text data -->
        <intent-filter>
            <action android:name="android.intent.action.SEND"/>
            <category android:name="android.intent.category.DEFAULT"/>
            <data android:mimeType="text/plain"/>
        </intent-filter>
        <!-- This activity also handles "SEND" and "SEND_MULTIPLE" with media data -->
        <intent-filter>
            <action android:name="android.intent.action.SEND"/>
            <action android:name="android.intent.action.SEND_MULTIPLE"/>
            <category android:name="android.intent.category.DEFAULT"/>
            <data android:mimeType="application/vnd.google.panorama360+jpg"/>
            <data android:mimeType="image/*"/>
            <data android:mimeType="video/*"/>
        </intent-filter>
    </activity>

    这个必须有<category android:name="android.intent.category.DEFAULT"/>, 其他的比如文本,信息文件发送,还有我们之前的View那种,基本上了解点就没什么大问题了。

    这个暂时到这里,然后看下category

    三、category的匹配规则

    1. 常用的就是android.intent.category.LAUNCHER, android.intent.category.DEFAULT,还会有android.intent.category.BROWSABLE

    BROWSABLE的意思就是浏览器在特定条件下可以打开你的activity:

      <intent-filter>
            <action android:name="android.intent.action.VIEW" />
            <category android:name="android.intent.category.DEFAULT" />
            <category android:name="android.intent.category.BROWSABLE" />
            <data
           android:scheme="http"
           android:mimeType="application/pdf"/>
    </intent-filter>

    在浏览器中输入 http://www.xxxxx.com/1.pdf ,那么这个activity自动被浏览器给调起来。

     

    特别说明:

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

    这二者共同出现,标明该Activity是一个入口Activity,并且会出现在系统应用列表中,二者缺一不可。

     类别
    一个包含应处理 Intent 组件类型的附加信息的字符串。 您可以将任意数量的类别描述放入一个 Intent 中,但大多数 Intent 均不需要类别。 以下是一些常见类别:
    CATEGORY_BROWSABLE
    目标 Activity 允许本身通过网络浏览器启动,以显示链接引用的数据,如图像或电子邮件。
    CATEGORY_LAUNCHER
    该 Activity 是任务的初始 Activity,在系统的应用启动器中列出。
    有关类别的完整列表,请参阅 Intent 类描述。
    
    您可以使用 addCategory() 指定类别。
    
    以上列出的这些属性(组件名称、操作、数据和类别)表示 Intent 的既定特征。 通过读取这些属性,Android 系统能够解析应当启动哪个应用组件。
    
    但是,Intent 也有可能会一些携带不影响其如何解析为应用组件的信息。 Intent 还可以提供:
    
    Extra
    携带完成请求操作所需的附加信息的键值对。正如某些操作使用特定类型的数据 URI 一样,有些操作也使用特定的 extra。
    您可以使用各种 putExtra() 方法添加 extra 数据,每种方法均接受两个参数:键名和值。您还可以创建一个包含所有 extra 数据的 Bundle 对象,然后使用 putExtras() 将Bundle 插入 Intent 中。
    
    例如,使用 ACTION_SEND 创建用于发送电子邮件的 Intent 时,可以使用 EXTRA_EMAIL 键指定“目标”收件人,并使用 EXTRA_SUBJECT 键指定“主题”。
    
    Intent 类将为标准化的数据类型指定多个 EXTRA_* 常量。如需声明自己的 extra 键(对于应用接收的 Intent),请确保将应用的软件包名称作为前缀。 例如:
    
    static final String EXTRA_GIGAWATTS = "com.example.EXTRA_GIGAWATTS";
    标志
    在 Intent 类中定义的、充当 Intent 元数据的标志。 标志可以指示 Android 系统如何启动 Activity(例如,Activity 应属于哪个任务),以及启动之后如何处理(例如,它是否属于最近的 Activity 列表)。
    如需了解详细信息,请参阅 setFlags() 方法。

    隐式启动的时候你就可以通过addCategory指定类别..

    注意:隐式的情况下action必须有一个,

    <category android:name="android.intent.category.DEFAULT" />也必须使用。

       <activity android:name="com.example.IntentFilterTestActvity2">
                <intent-filter>
                    <action android:name="com.google.test" />
                    <category android:name="fucksb2" />
                    <category android:name="android.intent.category.DEFAULT" />
                </intent-filter>
            </activity>

    然后匹配是,需要匹配:<category android:name="fucksb2" />

            Intent intent3 = new Intent();
            intent3.setAction("com.google.test");
            intent3.addCategory("fucksb2");
            startActivity(intent3);

    四、匹配优先级

       按照以下优先关系查找:action->data->category

    五、data匹配以及其他选项进一步说明(怕以后文章没了,所以粘贴内容过来,侵权的话记得联系我,然后保留链接就行):来自 blog.csdn.net/mynameish

         Intent Filter常见问题汇总
    
    (1)path、pathPrefix、pathPattern 之间的区别 
    
    path 用来匹配完整的路径,如:http://example.com/blog/abc.html,这里将 path 设置为 /blog/abc.html 才能够进行匹配; 
    pathPrefix 用来匹配路径的开头部分,拿上来的 Uri 来说,这里将 pathPrefix 设置为 /blog 就能进行匹配了; 
    pathPattern 用表达式来匹配整个路径,这里需要说下匹配符号与转义。 
    匹配符号: 
    “” 用来匹配0次或更多,如:“a” 可以匹配“a”、“aa”、“aaa”… 
    “.” 用来匹配任意字符,如:“.” 可以匹配“a”、“b”,“c”… 
    因此 “.*” 就是用来匹配任意字符0次或更多,如:“.*html” 可以匹配 “abchtml”、“chtml”,“html”,“sdf.html”… 
    转义:因为当读取 Xml 的时候,“/” 是被当作转义字符的(当它被用作 pathPattern 转义之前),因此这里需要两次转义,读取 Xml 是一次,在 pathPattern 中使用又是一次。如:“” 这个字符就应该写成 “//”,“/” 这个字符就应该写成 “////”。
    
    (2)查询是否有Activity可以匹配我们指定Intent的组件
    
    采用PackageManager的resolveActivity或者Intent的resolveActivity方法会获得最适合Intent的一个Activity 
    调用PackageManager的queryIntentActivities会返回所有成功匹配Intent的Activity
    
    (3)android.intent.action.MAIN 与android.intent.category.LAUNCHER的区别
    
    区别一: 
    android.intent.action.MAIN决定一个应用程序最先启动那个组件 
    android.intent.category.LAUNCHER决定应用程序是否显示在程序列表里(说白了就是是否在桌面上显示一个图标) 
    这两个属性组合情况: 
    第一种情况:有MAIN,无LAUNCHER,程序列表中无图标 
    原因:android.intent.category.LAUNCHER决定应用程序是否显示在程序列表里  
    第二种情况:无MAIN,有LAUNCHER,程序列表中无图标 
    原因:android.intent.action.MAIN决定应用程序最先启动的Activity,如果没有Main,则不知启动哪个Activity,故也不会有图标出现 
    所以这两个属性一般成对出现。 
    如果一个应用中有两个组件intent-filter都添加了android.intent.action.MAIN和 
    android.intent.category.LAUNCHER这两个属性, 则这个应用将会显示两个图标, 写在前面的组件先运行。 
    区别二:
    
    android.intent.category.LAUNCHER:android.intent.category.LAUNCHER决定应用程序是否显示在程序列表里,就是android开机后的主程序列表。 
    android.intent.category.HOME:按住“HOME”键,该程序显示在HOME列表里。
    
    (4)关于隐式intent
    
    每一个通过 startActivity() 方法发出的隐式 Intent 都至少有一个 category,就是 “android.intent.category.DEFAULT”,所以只要是想接收一个隐式 Intent 的 Activity 都应该包括 “android.intent.category.DEFAULT” category,不然将导致 Intent 匹配失败. 
    比如说一个activity组件要想被其他组件通过隐式intent调用, 则其在manifest.xml中的声明如下:
    
    
    
    <activity android:name="com.wooyun.org.MainActivity">
         <intent-filter>  
               <action android:name="com.google.test" />
               <category android:name="android.intent.category.DEFAULT" />
     </intent-filter> 
    </activity>
    
    ---------------------
    
    本文来自 猴子搬来的救兵Castiel 的CSDN 博客 ,全文地址请点击:https://blog.csdn.net/mynameishuangshuai/article/details/51673273?utm_source=copy 

    =============== End

  • 相关阅读:
    DispatcherServlet
    上转型对象
    Javascript闭包(Closure)
    跨域
    dict
    Python 函数参数传递方式
    协同过滤
    白话 动态规划 第一节 初识动态规划
    Spring@Autowired注解与自动装配
    protected
  • 原文地址:https://www.cnblogs.com/lsgxeva/p/13389770.html
Copyright © 2011-2022 走看看