现在的位置: 首页 > 综合 > 正文

精通Android4学习笔记-intent

2013年06月07日 ⁄ 综合 ⁄ 共 8047字 ⁄ 字号 评论关闭

精通Android4学习笔记-Intent

 

What is an intent? The short answer may be that an intent is an action with its associated data payload.

Intent是具有相关数据负载的action(操作)。

Intents List: Invoking Google Applications on Android Devices

http://developer.android.com/guide/appendix/g-app-intents.html

 

 

Intent的组成

  intent对象包含的内容:

   action

   data

      setData(Uri data)

      setDataAndType(Uri data, String type)

  extra

 

显式Intent

  带有组件名称

隐式Intent

  没有组件名称,但依赖于其他部分(比如action和data)

 

general action

   intent  action和他所调用的app之间存在一对一的关系吗?

   回答:intent action和他所调用的app之间有一对一的关系这是一种错觉。

action是一个抽象的概念,比如同样的Intent.ACTION_VIEW,根据data scheme的不同,可以对应于不同类别的app

 

Intent Action

intent data scheme

target app

Result

Intent.ACTION_VIEW

http

Browser

 

Intent.ACTION_VIEW

https

Browser

 

Intent.ACTION_VIEW

geo

Google Maps

 

Intent.ACTION_VIEW

google.streetview

Google Streetview

 

Intent.ACTION_CALL

tel

Dialer

 

Intent.ACTION_DIAL

tel

Dialer

 

Browser的activity注册了一个Intent,scheme是http和https

<activity......>
   <intent-filter>
        <action android:name="android.intent.action.VIEW" />
        <data android:scheme="http"/>
        <data android:scheme="https"/>
   </intent-filter>
</activity>

 结论:

   同样的Intent action,因为Intent data scheme不同,而对应于不同的target app;

   同样的target app,也可以对应于不同的Intent action;

 

data的更多信息

data元素的语法:

<data android:host="string

      android:mimeType="string

      android:path="string

      android:pathPattern="string

      android:pathPrefix="string

      android:port="string

      android:scheme="string" />

 mimeType是一个经常用到的特性

<intent-filter>
    <action android:name="android.intent.action.VIEW" />
    <data android:mimeType="vnd.android.cursor.dir/vnd.google.note" />
</intent-filter>

  这个Intent过滤器声明可以理解为“调用此活动来查看一组笔记”

<intent-filter>
    <action android:name="android.intent.action.VIEW" />
    <data android:mimeType="vnd.android.cursor.item/vnd.google.note" />
</intent-filter>

  这个Intent过滤器声明可以理解为“调用此活动来查看一条笔记”

Using Extra Information

   除了action和data以外,Intent还可以包括extra的附加特性。

  extra以键值对的形式表示。

 Using Components to Directly Invoke an Activity

  除了显式action启动activity,以及使用general action并借助URI来启动activity。

  android还提供了一种更直接的方式来启动活动:指定活动的ComponentName,这是围绕对象的包名和类名的抽象。

  setComponent(ComponentName name);

Intent intent = new Intent();

//注意,package name和class name都是fully qualified
intent.setComponent(new ComponentName("com.android.contacts","com.android.contacts.DialContactsEntryActivity");
startActivity(intent);

 相应的,AndroidManifest.xml中应该按照如下方式注册该activity

    <activity android:name=".BasicViewActivity"
                   android:label="Test Activity">

这里面没有Intent过滤器,直接通过类名或者组件名调用activity。这种类型的Intent被称为显式Intent。

显式Intent vs. 显式Action

Understanding Intent Categories

 CATEGORY_DEFAULT

 An activity can declare itself as a DEFAULT activity if it wants to be
invoked by implicit intents. If you don’t define this category for
your activity, that activity will need to be invoked explicitly every
time through its class name. This is why you see activities that get
invoked through generic actions or other action names that use
default category specification.

CATEGORY_LAUNCHER

Assigning this category to an activity will allow it to be listed on
the launcher screen.

CATEGORY_HOME

An activity of this type will be the home screen. Typically, there
should be only one activity of this type. If there are more, the
system will provide a prompt to pick one.

 

当使用Intent来启动Activity时,可以指定一种catagory来限定要选择的活动类型。也可以 搜索与某个catagory匹配的activity。

 

Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);

PackageManager pm = getPackageManager();
List<ResolveInfo> list = pm.queryIntentActivities(mainIntent, 0);

for(ResolveInfo ri: list)
{

//ri.activityInfo.
Log.d("test",ri.toString());
String packagename = ri.activityInfo.packageName;
String classname = ri.activityInfo.name;
Log.d("test", packagename + ":" + classname);
if (classname.equals("com.ai.androidbook.resources.TestActivity"))
{
  Intent ni = new Intent();
  ni.setClassName(packagename,classname);
  activity.startActivity(ni);
}

}

 Rules for Resolving Intents to Their Components

将Intent解析为组件的规则。我们讨论了action,data URI,extra,以及intent catagory.

android使用了多种策略,基于Intent过滤器来将Intent与它们的目标活动相匹配。

在此层次结构的顶部,只有一个Intent的component name。如果设置了此name,Intent就是显式Intent。对于显式Intent,重要的只是component name,Intent的所有其他方面或者特性都会被忽略。没有指定packagename的Intent是隐式的。解析隐式Intent对应的target component的规则非常多。

基本规则是,传入Intent的action,category和data特征必须匹配(或者呈现)Intent过滤器中指定的特征。

与Intent不同,一个Intent过滤器可以指定多个action,category和data特征。这意味着同一个intent filter可以满足多个Intent的需求,也就是说,一个action可以响应多个Intent。但是,匹配的含义在action,data特征和category之间各不相同。

action

data

  Intent过滤器中缺少data和缺少action的情况是相反的。如果intent filter中没有action,将匹配所有内容;如果intent filter中没有data,Intent中的每部分数据都不会匹配。下面详细说明了data中的各种特征。

data mime type 疑问 这部分还不是很明白

        数据类型区分大小写

       subtype

          可以使用*匹配所有subtypes

data scheme

    intent data scheme是intent data URI的一部分,intent没有另外的设置data scheme的方法。

    scheme也区分大小写。

If the data scheme of the incoming intent URI is content: or file:, it is considered a
match regardless of the intent filter scheme, domain, and path

data authority就是host authority

    <data android:host=www.somesite.com"/>

    授权也区分大小写

data path

    scheme,host和path协同验证传入Intent的URI,比如http://www.somesite.com/somepath,所以path host 和scheme不是孤立工作的,而是协同工作的。

   路径也区分大小写。

intent category

  传入的Intent中的每个category都必须存在于intent filter的catagory list中。intent filter中也可以包含更多类别。如果intent filter没有任何category,它只会与没有提交任何category的Intent匹配。

  注意:Android将所有传递给startActivity()的隐式Intent视为好像它们至少包含一个类别:android.intent.category.DEFAULT.如果传入的Intent为隐式Intent,startActivity()中的代码只会搜索定义了DEFAULT category的活动。所以每个希望通过隐式Intent调用的activity都必须在其intent filter中包含该DEFAULT category。

      <intent-filter>
           <action android:name="com.androidbook.intent.action.ShowBasicView"/>
           <category android:name="android.intent.category.DEFAULT" />
         </intent-filter>

疑问DEFAULT category是startActivity实现的一部分,而不是intent filter的内在行为。

 

对于从launcher screens调用的那些activity,不需要指定DEFAULT类别,不过也可以指定DEFAULT类别。这些活动的filter中可能仅仅包含MAIN和LAUNCHER category。

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

 练习使用ACTION_PICK

   调用另外一个activity,有时候需要返回结果。现在我们介绍一个稍微复杂的action,该action在调用之后返回一个值。ACTION_PICK就属于这类general action。

   ACTION_PICK的理念是启动一个活动来显示项列表。该activity然后应该允许用户从该列表中挑选一个项。用户挑选了项以后,activity应该向调用方返回所挑选选项的URI。这允许重用UI功能来选择某种类型的项。activity负责根据URI从ContentProvider获取数据。这也是数据应该尽可能封装到ContentProvider中的原因。

  此URI的实际MIME类型应该类似于:vnd.android.cursor.dir/vnd.google.note

  

练习使用ACTION_GET_CONTENT

 

Pending Inten t挂起的Intent

  这是Intent的变体。在PendingIntent中,Android支持组件将Intent存储在一个位置供以后使用,可从该位置再次调用它。

  看看如何创建PendingIntent

Intent regularIntent;

PendingIntent pi=  PendingIntent.getActivity(Context context, //originating context
            int requestCode, //0,1,2, 3, etc 这个参数用于区分两个PendingIntent
            Intent intent, //original intent
            int flags ) ;//flags

刚开始,我们一定会奇怪,创建一个PendingIntent为什么不是create方法而是get方法,而且更加奇怪的是这里是getActivity方法。

这个需要从常规Intent说起,常规Intent用于启动Activity/Service,或者调用BroadcastReceiver。使用Intent调用不同类型组件的性质是不同的。

为了解决这个问题,一个Android Context(superclass of Activity)提供了三种不同的方法。他们是

  • startActivity(Intent);
  • startService(Intent);
  • sendBroadcast(Intent);

有了这些变体,如果希望存储Intent供以后重用,在收到广播后,Android如何知道启动活动/启动服务还是启动广播接收程序?

这就是我们必须在创建PendingIntent时候,显式指定其用途的原因,他也就解释了以下三种独立方法的意义:

  • PendingIntent.getActivity(context,0,intent,...);
  • PendingIntent.getService(context,0,intent,...);
  • PendingIntent.getBroadcast(context,0,intent,...);

PendingIntent pi=  PendingIntent.getActivity(Context context, //originating context
            int requestCode, //0,1,2, 3, etc 这个参数用于区分两个PendingIntent
            Intent intent, //original intent
            int flags ) ;//flags

 

我们看看,同样内容的intent(不考虑extra包),会得到一样的PendingIntent。

   original intent的内部内容相匹配(除了extra包),就将他们视为相同。extra bundle可以不同,不会影响Intent的唯一性。如果你区别两个相同的original intent的pending intent,你可以使用不同的requestCode。

 

flags表示在存在PendingIntent时执行的操作-返回null,改写extra等。

   flags默认是0.

      FLAG_CANCEL_CURRENT,       如果已经有了一个相同内容的PI,就先取消原先的PI,再去创建一个新的PI;

      FLAG_ONE_SHOT,    这个PI仅仅只能被使用一次

      FLAG_NO_CREATE,   如果已经有了一个相同的PendingIntent,就返回null而不是去创建一个新的PI。

 
FLAG_UPDATE_CURRENT
, 和上面的不同之处在于,原先的PI会被更新extra data部分。

If you only need one PendingIntent active at a time for any of the Intents you will use, then you can alternatively use the flagsFLAG_CANCEL_CURRENT
orFLAG_UPDATE_CURRENT to either cancel or modify whatever current PendingIntent is associated with the Intent
you are supplying.

参考:http://developer.android.com/reference/android/app/PendingIntent.html

 

在20章的闹钟和23章的电话api中,我们都会说到PendingIntent,这对于我们加深理解PI的用法很有帮助。

 

抱歉!评论已关闭.