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

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

1. 解析隐式intent

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

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

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

 Intent startupIntent = new Intent(Intent.ACTION_MAIN);
startupIntent.addCategory(Intent.CATEGORY_LAUNCHER); PackageManager pm = getActivity().getPackageManager(); //查询包含Main操作和LAUNCHER类别的activity总数
List<ResolveInfo> activities = pm.queryIntentActivities(startupIntent, 0); 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。

设置列表项的点击事件

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

在使用包名和类名创建显式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添加一个标识。

  Intent i = new Intent(Intent.ACTION_MAIN)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
.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 。

安卓权威编程指南-笔记(第22章 深入学习intent和任务)的更多相关文章

  1. 安卓权威编程指南 -笔记(19章 使用SoundPool播放音频)

    针对BeatBox应用,可以使用SoundPool这个特别定制的实用工具. SoundPool能加载一批声音资源到内存中,并支持同时播放多个音频文件.因此所以,就算用户兴奋起来,狂按按钮播放全部音频, ...

  2. 安卓权威编程指南 -笔记(18章 处理assets)

    resources资源可以存储声音文件,但当处理多个音乐文件时,效率会很低. assets可以被看作随应用打包的微型文件系统,支持任意层次的文件目录结构.类似游戏这样需要加载大量图片和声音资源的应用通 ...

  3. 安卓权威编程指南-笔记(第21章 XML drawable)

    在Andorid的世界里,凡事要在屏幕上绘制的东西都可以叫drawable,比如抽象图形,Drawable的子类,位图图形等,我们之前用来封装图片的BitmapDrawable就是一种drawable ...

  4. 安卓权威编程指南-笔记(第27章 broadcast intent)

    本章需求:首先,让应用轮询新结果并在有所发现时及时通知用户,即使用户重启设备后还没有打开过应用.其次,保证用户在使用应用时不出现新结果通知. 1. 一般intent和broadcast intent ...

  5. 安卓权威编程指南-笔记(第23章 HTTP与后台任务)

    1. 网络连接基本 //通过指定URL获取原始数据,并返回一个字节流数组. public byte[] getUrlBytes(String urlSpec)throws IOException{ / ...

  6. 安卓权威编程指南-笔记(第24章 Looper Handler 和 HandlerThread)

    AsyncTask是执行后台线程的最简单方式,但它不适用于那些重复且长时间运行的任务. 1. Looper Android中,线程拥有一个消息队列(message queue),使用消息队列的线程叫做 ...

  7. 安卓权威编程指南 挑战练习 25章 深度优化 PhotoGallery 应用

    你可能已经注意到了,提交搜索时, RecyclerView 要等好一会才能刷新显示搜索结果.请接受挑战,让搜索过程更流畅一些.用户一提交搜索,就隐藏软键盘,收起 SearchView 视图(回到只显示 ...

  8. 安卓权威编程指南 - 第五章学习笔记(两个Activity)

    学习安卓编程权威指南第五章的时候自己写了个简单的Demo来加深理解两个Activity互相传递数据的问题,然后将自己的学习笔记贴上来,如有错误还请指正. IntentActivityDemo学习笔记 ...

  9. 安卓权威编程指南 挑战练习(第26章 在 Lollipop 设备上使用 JobService)

    26.11 挑战练习:在 Lollipop 设备上使用 JobService 请创建另一个 PollService 实现版本.新的 PollService 应该继承 JobService 并使用 Jo ...

随机推荐

  1. Android之布局LinearLayout

    1.weight属性用法 主要用于view对象屏幕适配比例 如下图,左边是等比例,右边是1:2比例 实现代码: <LinearLayout xmlns:android="http:// ...

  2. oBike退出新加坡、ofo取消免押金服务,全球共享单车都怎么了?

    浪潮退去后,才知道谁在裸泳.这句已经被说烂的"至理名言",往往被用在一波接一波的互联网热潮中.团购.O2O.共享单车.共享打车.无人货柜--几乎每一波热潮在退去后会暴露出存在的问题 ...

  3. MFC的combox禁止键盘输入

    项目中有个combox的下拉窗控件,鼠标双击总能存在焦点,并且会修改combox显示的文字,网上查了好多资料,都说修改style,可是我的vs2015里没发现有style的属性,后面修改 modal ...

  4. iOS 部分API理解

    - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typica ...

  5. 估计量|估计值|置信度|置信水平|非正态的小样本|t分布|大样本抽样分布|总体方差|

    5 估计量和估计值是什么? 估计量不是估计出来的量,是用于估计的量. 估计量:用于估计总体参数的随机变量,一般为样本统计量.如样本均值.样本比例.样本方差等.例如:样本均值就是总体均值的一个估计量. ...

  6. 跨域问题与SpringBoot解决方案

    什么是跨域? 定义:浏览器从一个域名的网页取请求另一个域名下的东西.通俗点说,浏览器直接从A域访问B域中的资源是不被允许的,如果想要访问,就需要进行一步操作,这操作就叫"跨域".例 ...

  7. 104)PHP,目录树状输出

    使用特定数量的缩进达到树状目的! 核心问题,计算需要缩进的数量! 缩进级别,与递归调用深度保持一致.每当执行一级递归操作,所找到的文件的缩进级别+; 语法实现: 增加一个参数,表示当前函数调用的深度级 ...

  8. REMODE解析

    版权声明:本文为博主原创文章,未经博主允许不得转载. 纯视觉的三维重建(不考虑用结构光的那一类)常用的有两大类方法:一类是SfM,缺点是计算量比较大,做不到实时运行:另一类是KinectFusion为 ...

  9. 关于虚拟机VMware Tools安装中出现的无法自动安装VMCI驱动程序的问题

    问题 解决方法 根据配置文件信息找到所在的虚拟机位置 找到后缀名为vmx的文件,右键打开方式中选择使用记事本打开 选择左上角编辑中的查找功能输入图中的查找内容后,点击查找下一个 将其原先的TRUE值改 ...

  10. firefox45版本与seleniumIDE

    firefox45版本与seleniumIDE https://blog.csdn.net/seanlyly/article/details/80203896 seleniumIDE与firefox版 ...