Android开发艺术探索--第一章生命周期和启动方式总结(2)

最近在拜读任主席的Android开发艺术探索,现在看了一半,再回头看前面的,感觉跟没有看一样,所以还是把知识点总结一下吧

Actvity的LaunchMode

  这节来讲一下Activity的启动方式,Activity有四种启动方式:standard、singleTop、singleTask、singleInstance。在默认情况下,多次启动同一个Activity的时候,系统会创建多个实例并把他们一一放入任务栈中,单击back键,这些Activity会一一回退。下面介绍一下这四种启动模式:

  • standard:标准模式,也是系统默认模式。每次启动不管是否存在都会新建一个实例,一个任务栈中可以有多个实例,每个实例也可以属于不同的任务栈。谁启动的Activity,这个Activity就运行在它的那个Activity所在的栈中。这里有一条需要注意的,当我们用ApplicationContext去启动standard模式的Activity时会报错:

    calling startActivity from outside of an Activity context requires the FLAG_ACTIVITY_NEW_TASK flag.Is this really what you want?

    这是因为standard模式的Activity默认会进入启动它的Activity所属的任务栈中,但是由于非Activity类型的Context并没有任务栈,所以就报错了。解决这个问题的方式是在Intent中addFlag–FLAG_ACTIVITY_NEW_TASK,这个时候的Activity是以singleTask模式启动的,放在一个新的任务栈中(这个问题碰到过几次,以前只知道要加上flag,但是没有仔细想过为什么,现在看到这块就豁然开朗了)

  • singleTop:栈顶复用模式。如果此模式的Activity当前位于任务栈的栈顶,那么再启动此Activity的时候不会重新创建, 但是会调用它的onNewIntent方法,此方法相当有用,如果此Activity不在栈顶,那么这时会再次创建实例
  • singleTask:栈内复用模式。这是一种单实例模式,在这种模式下,只要当前任务栈中有目标Activity,那么该Acticity不会被重新创建,同时它的onNewIntent方法会被回调,如果该Activity不在栈顶,则系统会把该Activity之上的元素全部退栈,此时该Activity调到栈顶。
  • singleInstance:单例模式,这是一种加强的singleTask模式,除了具有singleTask模式的所有特性之外,还加强了一点,具有此模式的Activity只能单独位于一个任务栈,并且此栈中只有此一个Activity

这里有一个参数需要说明一下TaskAffinity,这个参数标识了一个Activity归属哪个任务栈,默认情况下所有Avtivity所需要的任务栈的名字是包名,通过这个参数可以指定,这个参数通过配合singTask启动模式或者allowTaskReparenting属性配对使用,在其他情况下没有意义。具体说明看这篇博客android当中taskAffinity属性与launchMode相关。

再来说一下常用的几个Activity的Flags:

  • FLAG_ACTIVITY_NEW_TASK:指定singleTask启动模式,效果和XML中指定相同
  • FLAG_ACTIVITY_SINGLE_TOP:指定singleTop模式,效果和XML中指定相同
  • FLAG_ACTIVITY_CLEAR_TOP:当此标记位的Activity启动时,在同一个任务栈中所有位于它上面的Activity都要出栈,这个标记位一般会和singleTask启动模式一起出现,在这种情况下,被启动的Activity如果已经存在,那么系统就会调用它的onNewIntent。如果被启动的Activity采用standard模式,那么它连同它之上的Activity都要出栈,再重新创建新的Activity实例并放入栈顶。
  • FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS:具有这个标记的Activity不会出现在历史Activity的列表中,当某些情况下我们不希望用户通过历史列表回到我们的Activity的时候这个标记比较有用。

IntentFilter的匹配原则

  启动Activity的方式有两种:显示调用和隐式调用。显示调用就不多说了,来说一说隐式调用,隐式调用需要Intent能够匹配目标组件的IntentFilter中所设置的过滤信息。IntentFilter中的过滤信息有action、category、data,下面是一个过滤规则的示例:

<intent-filter>
    <action android:name="com.wpp.action"/>
    <category android:name="com.wpp.category"/>
    <data android:name="com.wpp.data"/>
</intent-filter>

  为了匹配过滤列表,需要同时匹配过滤列表中的action、category、data信息,否则匹配失败,一个过滤列表中的action、category、data可以有多个,只有完全匹配activity才能启动成功,另外,一个activity中可以有多个intent-filter,一个Intent只要能匹配任何一组intent-filter即可匹配成功。
  下面详细分析各种属性的匹配规则
  1. action的匹配规则
  action是个字符串,系统预定义了一些action,同时我们可以在应用中定义自己的action。action的匹配规则是Intent中的action必须能够和过滤规则中的action匹配,即字符串值完全一样,一个过滤规则中可以有多个action,只要任何一个action相同即可匹配成功。 如果Intent中没有指定action则匹配失败,注意,action区分大小写!
  2.category的匹配规则
  category也是字符串,跟action一样,系统有预定义的,我们也可以在应用中自定义。匹配规则和action不同,它要求Intent中如果含有category,则intent中所有的category都必须和一组intent-filter中的任何一个category完全匹配,如果没有category也可以匹配成功,但是一旦有category,不管几个,都必须和intent-filter中任何一个category匹配。为什么不设置category也可以匹配成功呢?因为系统在startActivity的时候会默认加上”android.intent.category.DEFAULT”这个category,为了我们的activity能够接收隐式调用,就必须在intent-filter中指定这个category
  3.data的匹配规则
  先了解一下data的结构:

<data android:scheme="string"
    android:host="string"
    android:port="string"
    android:path="string"
    android:pathPattern="string"
    android:pathPrefix="string"
    android:mimeType="string"/>

data由两部分组成,mimeType和URI,mimeType指媒体类型,比如image/jpeg、audio/mpeg4-generic和video/*等,可以表示图片、文本、视频等不同的媒体格式,而URI的结构:

<scheme>://<host>:<port>/[path]|[pathPattern]|[pathPrefix]
比如:http://www.baidu.com:80/search/info
  • Scheme:URI的模式,比如http、file、content等,如果URI中没有指定scheme,那么URI无效
  • Host:URI的主机名,如果Host没有指定,那么整个URI无效
  • Port:URI中的端口号,比如80,仅当URI指定了scheme和host参数的时候port参数才是有意义的
  • Path、pathPattern、pathPrefix:这三个参数表述路径信息,其中path表示完整的路径信息;pathPattern也表示完整的路径信息,但是它里面包含通配符”*”,表示0个或任意字符。由于正则表达式的规范,如果想表示真实的字符串,”*”要写成”\\*”,”\”要写成”\\\\”;path表示路径的前缀信息。

再讲一下匹配规则:
(1)如下过滤规则

<intent-filter>
    <data android:mimtType="image/*"/>
    ……
</intent-filter>

这种规则制定了媒体类型为所有类型的图标,那么Intent中的mimeType属性必须为”image/*”才能匹配,这种清下虽然过滤规则中没有指定URI,但是却有默认值,URI的默认值为content和file,示例比如:

intent.setDataAndType(Uri.parse("file://abc"),"image/png")

如果要为Intent指定完整的data,必须要调用setDataAndType方法,不能分开调用,因为setData和setType会彼此清除对方的值
(2)如下过滤规则

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

这种规则指定了两组data规则,且每个data都指定了完整的属性值,既有URI,又有mimeType,示例如下:

intent.setDataAndType(Uri.pase("http://abc"),"video/mpeg")
或者
intent.setDataAndType(Uri.parse("http://abc"),"audio/mpeg")

IntentFilter的过滤规则已经讲完了,这里有个地方需要注意一下,如果通过隐式调用来启动activity,当intent匹配不到activity的时候会报错,提示无法找到activity,所以通常情况下,当我们需要通过隐式调用来启动一个activity时,需要先做一下判断,方法有两种:通过PackageManager的resolveActivity或者Intent的resolveActivity方法,如果找不到匹配的Activity就会返回null,我们再来做处理就能避免activity找不到的错误了。另外,PackageManager还提供了queryIntentActivities方法,这个方法返回所有匹配的Activity信息。

public abstract List<ResolveInfo> queryIntentActivities(Intent intent, int flags);

public abstract ResolveInfo resolveActivity(Intent intent, int flags);

第二个参数要使用MATCH_DEFAULT_ONLY这个标记位,这个标记位含义是仅仅匹配那些在intent-filter中声明了DEFAULT这个category的Activity,使用这个标记位只要上面两个不返回null,那么startActivity一定成功。在action和category中,有一类action和category比较重要,

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

二者同时作用来标记一个入口activity。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值