zoukankan      html  css  js  c++  java
  • 安卓权威编程指南-笔记(第22章 深入学习intent和任务)

    本章,我们会使用隐式intent创建一个替换android默认启动器的应用。名为NerdLauncher。

    NerdLauncher应用能列出设备上的其他应用,点选任意列表项会启动相应应用。

    1. 解析隐式intent

    可启动的主 activity 都有包含 MAIN 操作和 LAUNCHER 类别的 intent 过滤器,一般在 AndroidManifest.xml 中的形式如下:

    1 <activity android:name=".XXXXActivity">
    2     <intent-filter>
    3         <action android:name="android.intent.action.MAIN"/>
    4         <category android:name="android.intent.category.LAUNCHER"/>
    5     </intent-filter>
    6 </activity>

    可以建立一个Intent,然后从PackageManager那里获取匹配它的所有activity。

    1 Intent startupIntent = new Intent(Intent.ACTION_MAIN);
    2 startupIntent.addCategory(Intent.CATEGORY_LAUNCHER);
    3 
    4 PackageManager pm = getActivity().getPackageManager();
    5 
    6 //查询包含Main操作和LAUNCHER类别的activity总数
    7 List<ResolveInfo> activities = pm.queryIntentActivities(startupIntent, 0);
    8 
    9 Log.i(TAG, "Found " + activities.size() + "activities");

    在CriminalIntent应用中,为使用隐式intent发送crime报告,我们先创建隐式intent,再将其封
    装在选择器intent中,最后调用 startActivity(Intent) 方法发送给操作系统:

    Intent i = new Intent(Intent.ACTION_SEND);
    ... // Create and put intent extras
    i = Intent.createChooser(i, getString(R.string.send_report));
    startActivity(i);

    这里没有使用类似的处理方式。原因是MAIN/LAUNCHER intent过滤器可能无法与通过 startActivity(...) 方法发送的 MAIN/LAUNCHER 隐式intent相匹配。

    startActivity(Intent)意味着启动匹配隐式intent的默认activity。调用 startActivity(Intent) 方法(或 startActivity-ForResult(...) 方法)发送隐式intent时,操作系统会悄悄为目标intent添加 Intent.CATEGORY_DEFAULT 类别。

    因此,如果希望intent过滤器匹配 startActivity(...) 方法发送的隐式intent,就必须在对应的intent过滤器中包含 DEFAULT 类别。

    然而定义了 MAIN/LAUNCHER intent过滤器的activity是应用的主要入口点。它只负责做好作为应用主要入口点要处理的工作。它通常不关心自己是否为默认的主要入口点,所以可以不包含CATEGORY_DEFAULT 类别。

    所以,我们转而使用intent直接向PackageManager 查询带有 MAIN/LAUNCHER intent过滤器的activity。

    2. 在运行时创建显示intent

    要创建启动activity的显示intent,需要从ResolveInfo对象中获取activity的包名和类名。这些信息可以从ResloveInfo对象的ActivityInfo中获取。

    接下来实现用户点击任意列表项,启动对应的activity,我们需要使用显式intent来启动activity。

    设置列表项的点击事件

     1  @Override
     2         public void onClick(View v){
     3             ActivityInfo activityInfo = mResloveInfo.activityInfo;
     4             /*
     5            *     发送了ACTION_MAIN操作。发送的intent是否包含操作,对大多数app来说没什么区别。
     6             *    不过,有些应用的启动行为可能会有所不同。取决于不同的启动要求,同样的activity可能会显示不同的用户界面。开发人员最好能明确启动意图,以便让activity完成它应该完成的任务。
     7              */
     8             Intent i = new Intent(Intent.ACTION_MAIN)
     9                     .setClassName(activityInfo.applicationInfo.packageName,activityInfo.name);
    10 
    11             startActivity(i);
    12         }

    在使用包名和类名创建显式intent时,我们使用了以下intent方法:

    public Intent setClassName(String packageName, String className);

    此方法和Intent构造方法public Intent(Context packageContext, Class<?> cls)结果相同,都是为 Intent 添加了 ComponentName。

    也可以自己通过包名和类名创建 ComponentName ,然后使用下面的 Intent 方法创建显式:

    public Intent setComponent(ComponentName component)

    不过setClassName方法能够自动创建组建名,所以使用该方法需要的实现代码相对较少。

    2.任务与后退栈

    任务是用户比较关心的activity栈。栈底部的activity通常称为基activity。用户可以看到栈顶的activity。用户点击后退键时,栈顶activity会弹出栈外。如果当前屏幕上显示的是基activity,点击后退键,系统会退回主屏幕。在当前任务中启动activity的好处是,用户可以在任务内而不是在应用层级间导航返回.默认情况下,新 activity 都在当前任务中启动。在 CriminalIntent 应用中,无论何时启动新 activity,它都会被添加到当前任务中。即使要启动的 activity 不属于本应用,它同样也在当前任务中启动。

    2.1在任务间切换

    在不影响各个任务状态的情况下,overview screen可以让我们在任务间切换。例如,如果进入联系人应用,然后切换到Twitter应用查看信息,这时我们就启动了两个任务。如果再切换回联系人应用,我们在两项任务中所处的状态位置都会被保存下来。

    清除任务就是从应用回退栈中清除所有activity。

    2.2 启动新任务

    我们需要NerdLauncher在新任务中启动activity,这样,点击NerdLauncher启动器中的应用列表项可以让应用拥有自己的任务,用户因此可以在运行的应用间自由切换。

    为了在启动新activity时启动新任务,需要为intent添加一个标识

    1  Intent i = new Intent(Intent.ACTION_MAIN)
    2                     .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
    3                     .setClassName(activityInfo.applicationInfo.packageName,activityInfo.name);

    2.3 使用 NerdLauncher 应用作为设备主屏幕

    只需要在项目的配置文件AndroidManifest.xml,对找代码清单向主过滤器添加以下节点

    <category android:name="android.intent.category.HOME" />
    <category android:name="android.intent.category.DEFAULT" />

    通过添加 HOME 和 DEFAULT 类别定义,NerdLauncher应用的activity会成为可选的主界面。

    3. 进程与任务

    进程是操作系统创建的,供应用对象生存以及应用运行的地方。

    每一个activity实例都仅存在于一个进程和一个任务中,这也是进程与任务的唯一相似之处。任务只包含activity,这些activity通常来自于不同的应用。而进程则包含了应用的全部运行代码和对象。

    进程与任务很容易让人混淆,主要原因在于它们不仅在概念上有某种重叠,而且通常都是以其所属应用的名称被人提及的。我们以短信应用和联系人应用为例,看看以下具体场景就会明白了(首先清理掉 overview screen 中的所有任务)。 
    打开短信应用:这里我们新建了一个任务,也新建了一个短信的进程 
    点击选择收件人,这会打开联系人应用让我们选择目标联系人: 我们仍然只有一个短信任务,其中包含了两个应用的 activity,也就是说新建了联系人的进程,这样便有了两个进程 
    直接切回主界面(而不是后退回去),打开联系人应用:这样,我们多了一个联系人的任务,并且在联系人进程中新增了一个联系人 activity 的实例。

    此外,Android 并没有提供方法用来终止任务,不过,我们可以终止进程。应用商店中那些宣称自己是任务终止器的应用,实际上都是进程终止器。

    4. 并发文档

    在Lollipop设备上,对以 android.intent.action.SEND 或 action.intent.action.SEND_MULTIPLE 操作启动的activity,隐式intent选择器会创建独立的新任务。(在旧设备上,Gmail的activity是直接添加给CriminalIntent应用任务的。)

    这种现象要归因于Lollipop中叫作并发文档(concurrent documents)的新概念。

    有了并发文档,我们就可以在应用运行时动态创建任意数目的任务。在Lollipop之前,应用任务只能预先定义好,而且还要在manifest文件中明确指定。

    在Lollipop设备上,如果需要应用启动多个任务,可采用两种方式:给intent打上 Intent.FLAG_ACTIVITY_NEW_DOCUMENT 标签,再调用 startActivity(...) 方法;或者在manifest文件中,为activity设置如下 documentLaunchMode :

    <activity
    android:name=".CrimePagerActivity"
    android:label="@string/app_name"
    android:parentActivityName=".CrimeListActivity"
    android:documentLaunchMode="intoExisting" />

    使用上述方法,一份文档只会对应一个任务。(如果发送带有和已存在任务相同数据的intent,系统就不会再创建新任务。)如果无论如何都想创建新任务,那就给intent同时打上Intent.FLAG_ACTIVITY_NEW_DOCUMENT 和 Intent.FLAG_ACTIVITY_MULTIPLE_TASK 标签,或者把manifest文件中的 documentLaunchMode 属性值修改为 always 。

  • 相关阅读:
    bootstrap表头固定
    JS:二维数组排序和获取子级元素
    JavaScript 变量声明提升
    一道经典面试题-----setTimeout(function(){},0)
    排序
    基础知识:Promise(整理)
    几个兼容相关的重要函数
    JSON
    关于由ajax返回的数据在for循环中只能取到最后一个数的问题
    如果要遍历除了for循环,你还知道什么?——JavaScript的各种遍历方式
  • 原文地址:https://www.cnblogs.com/chase1/p/7201518.html
Copyright © 2011-2022 走看看