Android汇总总结

Android启动模式

2016-04-18  本文已影响468人  Utopia_Sen

在介绍 Android 启动模式之前,先介绍两个概念,一个是 task ,另一个是在 Androidmanifest 文件中 <activity> 的一个重要属性, taskAffinity

先初浅地了解一下这两个概念,接下来会对它们进行详细的解读。

Android有以下四种启动模式:

<?xml version="1.0" encoding="utf-8"?>
<manifest package="com.chen.activitylaunchtest"
  xmlns:android="http://schemas.android.com/apk/res/android">       
  <application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:supportsRtl="true"
    android:theme="@style/AppTheme">
    <activity android:name=".MainActivity"
              android:taskAffinity="com.chen.main">
      <intent-filter>
        <action android:name="android.intent.action.MAIN"/>
        <category android:name="android.intent.category.LAUNCHER"/>
      </intent-filter>
    </activity>
    <activity android:name=".SecondActivity"
              android:launchMode="standard"></activity>
    <activity android:name=".ThirdActivity"></activity>
  </application>
</manifest>

我们打开 MainActivity ,再从 MainActivity 跳转到 SecondActivity ,并启动 SecondActivity 两次。得到任务栈活动如下图:


standard.png

可以看出,
- 当 MainActivity 启动时, MainActivity 的 taskAffinity 指定为 com.chen.main ,所以上图任务栈的名称为 com.chen.main 。
- 又从 MainActivity 中启动 SecondActivity ,上面有说过, activity A 启动了 activity B , activity B 则会运行在 activity A 所在的任务栈中。所以 SecondActivity 会在 MainActivity 的任务栈中启动。
- 因为在 standard 模式下,每次启动一个 Activity ,都会重新创建新的实例,不管这个实例在任务中是否已经存在,所以任务栈中有三个 SecondActivity 的实例。

在一开始还提到, taskAffinity 属性一般和 singleTask 模式或者 allowTaskReparenting 属性配对使用。 taskAffinity 属性和 allowTaskReparenting 属性配对使用是一个怎样的工作过程呢?场景如下:

比如现在有 2 个应用 A 和 B , A 启动了 B 的一个 Activity C , Activity C 的 allowTaskReparenting 属性为 true ,然后按 Home 键回到桌面,然后再单击 B 的桌面图标,这个时候并不是启动了 B 的主 Activity ,而是重新显示了已经被应用 A 启动的 Activity C ,或者说, C 从 A 的任务栈转移到了 B 的任务栈中。
可以这么理解,由于 A 启动了 C ,这个时候 C 只能运行在 A 的任务栈中,但 C 属于 B 应用,正常情况下,它的 taskAffinity 属性值肯定不可能和 A 的任务栈相同(因为包名不同)。所以当 B 启动后, B 会创建自己的任务栈,这个时候系统发现 C 的原本所想要的任务栈已经被创建了,所以把 C 从 A 的任务栈中转移过来。

两种方法能给 Activity 指定启动模式

  1. 通过 AndroidMenifest 给 Activity 指定启动模式:
<activity android:name=".SecondActivity"
           android:launchMode="singleTask"></activity>
  1. 通过在 Intent 中设置标志位来为 Activity 指定启动模式:
Intent intent = new Intent(MainActivity.this, SecondActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);

常用的 Activity 的 Flags 有

**显式启动 Activity **

Intent intent = new Intent(MainActivity.this, SecondActivity.class);
startActivity(intent);

**隐式启动 Activity **
需要在 AndroidMenifest 里面为 Activity 设置 IntentFilter 匹配规则,并且intent也要添加过滤器。

<activity android:name=".SecondActivity"          
          android:launchMode="singleTask">    
  <intent-filter>        
    <action android:name="android.intent.action.VIEW"></action>        
    <category android:name="android.intent.category.DEFAULT"></category>        
    <data android:scheme="http"              
          android:pathPattern=".*\\.jpg"              
          android:mimeType="image/jpg">        
    </data>    
  </intent-filter>
</activity>
Intent intent = new Intent();
intent.setAction("android.intent.action.VIEW");
intent.setDataAndType(Uri.parse("http://www.baidu.com/search/info/hello.jpg"), "image/jpg");
startActivity(intent);

** IntentFilter 的匹配规则**

data 由两部分组成, mimeType 和 URL 。
- mimeType 指媒体类型,比如 image/jpeg 和 video 等,可以表示图片、文本、视频等不同的媒体格式。
- URL 的结构
><scheme>://<host>:<port>/[<path>|<pathPrefix>|<pathPattern>]

  例如:**```http://www.baidu.com:80/search/info/hello.jpg```**
  Scheme: URI 的模式,比如 http ,file,content 等,如果 URI 中没有指定 scheme ,那么整个 URI 无效。在上述例子里,scheme="http"。
  Host:URI 的主机名,比如 www.baidu.com,如果 URI 没有指定 host,那么整个 URI 无效。在上述例子里,host="www.baidu.com"。
  Port:URI 中的端口号,比如 80。在上述例子里,port="80"。
  Path:表示完整的路径信息。在上述例子里,path="/search/info"。
  pathPrefix:表示路径的前缀信息。在上述例子里,pathPrifix="/search"。
  pathPattern:也可以表示完整的路径信息,但是它里面可以包含通配符。在上述例子里,pathPattern="\.\*\\\\.jpg"
    - 匹配符号:"\*" 用来匹配0次或更多,如:"a\*" 可以匹配"a"、"aa"、"aaa"...
    - "\." 用来匹配任意字符,如:"\." 可以匹配 "a"、"b","c"...
    - "\.\*" 就是用来匹配任意字符0次或更多,如:"\.\*chen" 可以匹配 "chen"、"androidchen" ...
    - 转义:因为当读取 Xml 的时候,"\\" 是被当作转义字符的(当它被用作 pathPattern 转义之前),因此这里需要两次转义,读取 Xml 是一次,在 pathPattern 中使用又是一次。如:"\*" 这个字符就应该写成 "\\\\*","\\" 这个字符就应该写成 “\\\\\\\\”。

- 例子:  如果我们想要匹配 http 以 ".jpg" 结尾的路径,使得别的程序想要打开网络 jpg 时,用户能够可以选择我们的程序进行下载查看。我们可以将 scheme 设置为 "http",pathPattern 设置为 "\.\*\\\\.jpg",整个 intent-filter 设置为:
```XML

<intent-filter>
<action android:name="android.intent.action.VIEW"></action>
<category android:name="android.intent.category.DEFAULT"></category>
<data android:scheme="http" android:pathPattern=".*\.jpg"></data>
</intent-filter>
如果你只想处理某个站点的 jpg,那么在 data 标签里增加android:host="yoursite.com"则只会匹配http://yoursite.com/xxx/xxx.jpg```,但这不会匹配www.yoursite.com,如果你也想匹配这个站点的话,你就需要再添加一个 data 标签,除了 android:host 改为 "www.yoursite.com" 其他都一样。

  1. 要注意的事项
- 如果要为 Intent 指定完整的 data,必须要调用 setDataAndType 方法,不能用 setData 再调用 setType,因为这两个方法彼此会清除对方的值。
```java
intent.setDataAndType (Uri.parse ("http://www.baidu.com/search/info/hello.jpg"), "image/jpg");
```
- Intent-filter 的匹配规则对于 Service 和 BroadcastReceiver 也是同样的道理,不过系统对于 Service 的建议是尽量使用显式调用方式来启动服务。
- 通过隐式方式启动一个 Activity 时,可以采用 PackageManager 的 resolveActivity 方法或者 Intent 的 resolveActivity 方法先做一下判断,判断是否有 Activity 能匹配隐式 Intent。
```java

Intent intent = new Intent();
intent.setAction("android.intent.action.VIEW");
intent.setDataAndType(Uri.parse("http://www.baidu.com/search/info/hello.jpg"), "image/jpg");
if (intent.resolveActivity(getPackageManager()) == null)
Log.d("LaunchTest", "Go to SecondActivity unsuccessfully.");
else
startActivity(intent);
```

上一篇 下一篇

猜你喜欢

热点阅读