【笔记】【从Android Guide温习Android 三】意图 (Intent)

 

【笔记】【从Android Guide温习Android 三】意图 (Intent)

官方网站链接html

是什么

直译过来很贴切"意图". 主要用于启动Activity,Service以及Broadcast。java

分类

  • 显式Intentandroid

    明确你意图的目标。即指明你要通知的对象,是哪一个Activity或是Serviceweb

  • 隐式Intentapp

    你的意图不明确,但须要符合你相应的条件。好比发送Broadcast.ide

建立Intent

包含下面几大部分函数

前四种(Component name. Action, Data, Category),系统经过这些属性判断启动哪一个组建(Component)。测试

  • Component name网站

    目标组建, 注意这个参数是 ComponentName 类,该类由包名和类名组成。ui

    你一般调用以下方法:

    // case 1
      Intent intent = new Intent(this, IntentActivity.class);
      // case 2
      Intent intent = new Intent();
      intent.setComponent(new ComponentName(stringOfPackage, stringOfClass));
      // case 3
      Intent intent = new Intent();
      intent.setClassName(stringOfPackage, stringOfClass)
  • Action

    "意图"执行的具体活动。能够理解为一种标识。每一种有本身的含义。Intent提供给咱们一些公用的Action。

    由于Intent能够携带数据,因此每种公用Action也表明是否有输入输出数据。

    同时,Intent有两种分类,一种被Activity使用, 另外一种为Broardcast所用。

    下面举几个例子,文尾会附上全部Action。

    Activity:

    • ACTION_MAIN: 标识程序入口。没有数据返回。

    • ACTION_VIEW: 展现用户数据。可设置输入的URI用来接受数据。

    • ACTION_INSERT: 插入一条空数据到所提供的容器。输入的URI是待插入数据的目录。

    • ACTION_EDIT: 为传入数据,提供明确的可修改的访问。输入的URI是待修改的数据。

      最后两个或许看上不是很明白。
        能够结合ContentProvider去理解。
        插入或修改数据,须要告诉Provider一个URI.该URI标识出你要插入或修改的表或行数据。
        因此你若启动一个Activity去完成此操做,灵活性的方法是给他待操做的URI。

    BroadCast:

    • ACTION_MEDIA_BAD_REMOVAL: 移动媒体到SD卡时,要移动的目标位置是unmounted的。

    • ACTION_MEDIA_BUTTON: 点击"Media Button"

    • ACTION_MEDIA_REMOVED: 媒体被删除。

  • Data

    指向该数据的URI或MIME类型。

    • setData() 设置URI

    • setType() 设置MIME

    • 上述两函数互斥的,若需同时设置这两项,须要经过 setDataAndType()。

  • Category

    标识目标组建的分类。多数状况下不须要此参数,固然,需不须要确定依赖于你AndroidManifest中的设置。

  • Extras

    须要携带的数据经过此属性存储。

    经过putExtra() 存入, getXXXExtra()读取

    在这里扫个盲,原来被某测试同窗问了屡次,关于putExtra和putExtras是否同样,估计是由于不清楚putExtra最终存到了哪里。直接上源码:

    // putExtra() 和 putExtras() 是等价的。
      public Intent putExtra(String name, boolean value) {
          if (mExtras == null) {
              mExtras = new Bundle();
          }
          mExtras.putBoolean(name, value);
          return this;
      }
      public Intent putExtras(Bundle extras) {
          if (mExtras == null) {
              mExtras = new Bundle();
          }
          mExtras.putAll(extras);
          return this;
      }
      public Intent putExtras(Intent src) {
          if (src.mExtras != null) {
              if (mExtras == null) {
                  mExtras = new Bundle(src.mExtras);
              } else {
                  mExtras.putAll(src.mExtras);
              }
          }
          return this;
      }
    
      // Bundle putXXX
      // mMap type is ArrayMap<String, Object>()
      public void putLong(String key, long value) {
          unparcel();
          mMap.put(key, value);
      }
    
      //Bundle putAll method...
      public void putAll(Bundle map) {
          unparcel();
          map.unparcel();
          mMap.putAll(map.mMap);
          // fd state is now known if and only if both bundles already knew 
          mHasFds |= map.mHasFds;
          mFdsKnown = mFdsKnown && map.mFdsKnown;
      }
  • Flags

    终于见到"万能的"flag了。

    官网举了两个例子:

    • 系统如何加载Activity, 如Activity应该加入到哪一个任务中

    • 加载后有什么操做, 如是否加入到最近的Activity.

隐式Intent如何肯定目标组建的

影响因素有如下几点:

  • Action

    在Manifest中的intent-filter节点中,定义0个或多个action节点,以下.

    <intent-filter>
          <action android:name="android.intent.action.EDIT" />
          <action android:name="android.intent.action.VIEW" />
          ...
      </intent-filter>

    匹配原则

    查找包含的name属性是否与请求的intent相同,相同则进行下面的判断。
  • Category

    在Manifest中的intent-filter节点中,定义0个或多个category节点,以下.

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

    匹配原则

    查找包含的name属性是否与请求的intent相同,相同则进行下面的判断。

    当隐式intent是要启动某个Activity时,默认会添加 CATEGORY_DEFAULT 分类

    因此被启动的Activity要在intent-filter中加上"android.intent.category.DEFAULT"这个分类。

  • Data

    在Manifest中的intent-filter节点中,定义0个或多个data节点,以下.

    <intent-filter>
          <data android:mimeType="video/mpeg" android:scheme="http" ... />
          <data android:mimeType="audio/mpeg" android:scheme="http" ... />
          ...
      </intent-filter>

    Data有两部分组成,一部分是 URI 另外一部分是 MIME

    URL由这些4大属性组成: scheme, host, port, path.

    下面是官方的例子,URI与属性的对应图

    content://com.example.project:200/folder/subfolder/etc
      ------- | -------------------|---|--------------------
      scheme  |        host        |port|       path

    4大属性依次依赖,前者若没有声明,后者的设置将被忽略。

    URI的比较原则:仅比较intent的URI包含的部分。即若只包含scheme则匹配scheme,包含scheme和host则比较二者。

    Path的模糊匹配:* 能够匹配全部。

    匹配原则:比较复杂。

    下表 - 标识未声明此属性,+ 标识已声明。 当四条均符合是,则匹配成功。

    URI MIME 命中组建条件(URI) 命中组建条件(MIME)
    - - - -
    + - + -
    - + - +
    + + + +

    还有不少细节,请参照官网,Note如下的部分。

匹配Intent

官网举了两点例子,第二点会结合个人代码说明。

  • Android如何确认打开app时应选择那个组建首先启动。

    • ACTION_MAIN

    • CATEGORY_LAUNCHER

  • 能够利用方法查找符合intent的组建。

    PackageManager中的 query...() 和 resolve...()

    //获取符合的intent并显示在ListView中。
    
      public static final String INTENT_FILTER = "com.tangyu.component.demo.action";                                                                              
    
      // method start ...
      mVList = (ListView) findViewById(R.id.demo_launcher_list);
      List<ResolveInfo> resolveInfoList = getPackageManager().queryIntentActivities(new Intent(INTENT_FILTER, null), 0);
    
       LinkedList<String> activities = new LinkedList<String>();
       for (int i = 0; i < resolveInfoList.size(); ++i) {
           String fullname = resolveInfoList.get(i).activityInfo.name;
           Pattern pattern = Pattern.compile("\\.");
           String[] split = pattern.split(fullname);
           String activityName = split[split.length - 1]; 
           activities.add(activityName);
       }   
       mVList.setAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, activities));
      // method end.

PendingIntent

是Intent的包装类,获取外界APP的信任权限,并使用携带的intent启动他。内容仍是比较多的。之后在系统复习。

例子

官网的例子很到位的说

  • 显式Intent 用Download服务为例,传入URI进行download。

  • 隐式Intent 要Share某些数据,如有匹配的Activity,则启动它。

  • 其中也介绍了 App chooser 这个比较直观的体现隐式的含义。

  • 接收显式Intent

    在AndroidManifest.xml中设置<intent-filter>, 下面是官网的例子

    <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>
    
      <!-- 看!!是能够设置多个不一样的intent-filter -->
      <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>

    下面是TYComponent项目的AndroidManifest.xml

    <activity android:name=".demo.DemoLauncher">
              <intent-filter>
                  <action android:name="android.intent.action.MAIN"/>
                  <category android:name="android.intent.category.LAUNCHER"/>
              </intent-filter>
          </activity>
          <!-- horizontal list view -->
          <activity
              android:name=".demo.HorizontalListViewDemo"
              android:label="@string/app_name">
              <intent-filter>
                  <action android:name="com.tangyu.component.demo.action"/>
              </intent-filter>
          </activity>
          <activity
              android:name=".demo.HorizontalListViewDemo4Grid"
              android:label="@string/app_name">
              <intent-filter>
                  <action android:name="com.tangyu.component.demo.action"/>
              </intent-filter>
          </activity>
    
          <!-- remind service -->
          <activity android:name=".demo.service.remind.ActDemoRemindService"
                    android:label="@string/app_name">
              <intent-filter>
                  <action android:name="com.tangyu.component.demo.action"/>
              </intent-filter>
          </activity>

    除了Launcher之外,组建都会有<action android:name="com.tangyu.component.demo.action"/>

    这是为了实现获取具备相同Action的组建,并把他们显示到列表中。学自于ApiDemo。

    再者,若将com.tangyu.component.demo.action 换为 android.intent.action.MAIN 会不会有影响?

    不会有影响,虽然组建都是程序的入口。可是因为第一个有<category android:name="android.intent.category.LAUNCHER"/> ,因此打开应用,还是从demo.DemoLauncher启动。

    在这里有一下几点须要注意

    1. 显式意图会直接送给目标,不会管该组建的Intent-filters

    2. 避免运行其余APP的组建,一般用显式意图启动组建

    3. 全部的Activity的intent-filters都要定义在AndroidManifest中,可是broadcast的filter能够动态绑定。经过 registerReceiver()) 和 unregisterReceiver());

    4. 若是你不想让其余APP启动你的组建,设置exported 为false

总结

  • Intent做为启动组建而存在。他携带不少信息,目标,数据,过滤。

  • Intent分为显式和隐式两种,表明做用目标是否明确。明确的用狙击枪,不明确的有冲锋枪。

  • Intent的匹配规则不少,要合理使用。

相关文章
相关标签/搜索