Android编程权威指南(第二版)学习笔记(二十二)—— 第22章 深入学习 intent 和任务

本章构建了一个最简单的 Launcher 应用,可以让我们深入理解 intent,intent 过滤器以及 Android 应用间的交互,还介绍了进程和任务的联系与区别。
�GitHub 地址:

完成第22章,未完成挑战
完成挑战


我们要构建一个 Launcher 应用,它的大概形式是一个列表,通过点击可以进入相应的应用,这个时候我们需要获取所有的可启动主 activity。

1. 解析隐式 intent

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


    
        
        
    

所以我们要建立一个 intent,然后用 PackageManager 来解析这个 intent,获取所有匹配的 activity。

Intent startupIntent = new Intent(Intent.ACTION_MAIN);
startupIntent.addCategory(Intent.CATEGORY_LAUNCHER);

PackageManager pm = getActivity().getPackageManager();
List activities = pm.queryIntentActivities(startupIntent, 0);

startActivity(Intent intent) 方法会在 Intent 对象中添加 Intent.CATEGORY_DEFAULT ,而一般的应用主 activity 可能不包含 CATEGORY_DEFAULT 类别,所以并不能用 startActivity 启动。

接下来要知道这些应用的名字,我们查询到的 ResolveInfo 对象中包含的 activity 标签都是可启动的主 activity, 那么其标签名一般也就是应用名。为了保证列表的美观,我们对这些 activity 的名字按首字母排序:

Collections.sort(activities, new Comparator() {
    @Override
    public int compare(ResolveInfo o1, ResolveInfo o2) {
        PackageManager pm = getActivity().getPackageManager();
        return String.CASE_INSENSITIVE_ORDER.compare(
                o1.loadLabel(pm).toString(),
                o2.loadLabel(pm).toString());
    }
});

2. 运行时创建显式 intent

在点击列表中某项的时候,我们要响应并打开,所以在 onClickListener 中添加显式的 intent,打开对应的 activity:

@Override
public void onClick(View v) {
    ActivityInfo activityInfo = mResolveInfo.activityInfo;

    Intent i = new Intent(Intent.ACTION_MAIN)
            .setClassName(activityInfo.applicationInfo.packageName,
                    activityInfo.name);

    startActivity(i);
}

我们使用了方法 setClassName ,使用包名和类名创建一个 Intent 对象

public Intent setClassName(String packageName, String className)

该方法和一个 Intent 的构造方法 public Intent(Context packageContext, Class cls)结果相同,都是为 Intent 添加了 ComponentName,当然,Intent 本身也有一个 setComponent 的方法。使用 setClassName 能够自动创建 ComponentName,所需要的实现代码相对较少。

3. 任务与后退栈

首先给出定义,任务:acivity 栈。

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

3.1 任务间切换

一般来说,我们使用 overview screen 在任务间切换,或者关闭某项任务。

overview 的其他叫法还有:任务管理器、最近使用屏、最近应用、最近任务等,启动方法就是点击 Recents 按钮,一般是个方块或者连个重叠的长方形。

3.2 启动新任务

因为我们做一个 Launcher 应用,所以要为打开的 activity 新建一个任务。所以需要在建立 intent 的时候添加一个标志:

@Override
public void onClick(View v) {
    ActivityInfo activityInfo = mResolveInfo.activityInfo;

    Intent i = new Intent(Intent.ACTION_MAIN)
            .setClassName(activityInfo.applicationInfo.packageName,
                    activityInfo.name)
            // 添加一个 New Task 的标识就能在启动时新建一个任务
            .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

    startActivity(i);
}

3.3 将应用作为设备的主界面

只要在 Manifest 文件中的 标签中添加值为 HOME 和 DEFAULT 的 category 即可

4 进程

4.1 进程是什么

对象需要内存和虚拟机的支持才能存在。进程是操作系统创建的、供应用对象生存以及应用运行的地方。进程通常占用由操作系统管理着的系统资源,如内存、网络端口以及打开的文件等。进程还拥有至少一个(可能多个)执行线程。在 Android 系统中,进程总会有一个运行的虚拟机。

尽管存在未知的异常情况,但总的来说,Android 世界里的每个应用组件都仅与一个进程相关联。应用伴随着自己的进程一起完成创建,该进程同时也是应用中所有组件的默认进程。
(虽然组件可以指派给不同的进程,但我们推荐使用默认进程。如果确实需要在不同进程中运行应用组件,通常也可以借助多线程来达到目的。相比多进程的使用,Android 多线程的使用更加简单。)

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

4.2 进程和任务的区别

进程与任务很容易让人混淆,主要原因在于它们不仅在概念上有某种重叠,而且通常都是以其所属应用的名称被人提及的。我们以短信应用和联系人应用为例,看看以下具体场景就会明白了(首先清理掉 overview screen 中的所有任务)。

  • 打开短信应用:这里我们新建了一个任务,也新建了一个短信的进程
  • 点击选择收件人,这会打开联系人应用让我们选择目标联系人: 我们仍然只有一个短信任务,其中包含了两个应用的 activity,也就是说新建了联系人的进程,这样便有了两个进程
  • 直接切回主界面(而不是后退回去),打开联系人应用:这样,我们多了一个联系人的任务,并且在联系人进程中新增了一个联系人 activity 的实例。

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


GitHub Page: kniost.github.io
:http://www.jianshu.com/u/723da691aa42

你可能感兴趣的:(Android编程权威指南(第二版)学习笔记(二十二)—— 第22章 深入学习 intent 和任务)