在Android应用程序中,可以配置Activity以四种方式来启动,其中最令人迷惑的就是singleTask这种方式了,官方文档称以这种方式启动的Activity总是属于一个任务的根Activity。果真如此吗?本文将为你解开Activity的singleTask之谜。在解开这个谜之前,我们先来简单了解一下在Android应用程序中,任务(Task)是个什么样的概念。我们知道,Activity是Android应用程序的基础组件之一,在应用程序运行时,每一个Activity代表一个用户操作。用户为了完成某个功能而执行的一系列操作就形成了一个Activity序列,这个序列在Android应用程序中就称之为任务,它是从用户体验的角度出发,把一组相关的Activity组织在一起而抽象出来的概念。对初学者来说,在开发Android应用程序时,对任务的概念可能不是那么的直观,一般我们只关注如何实现应用程序中的每一个Activity。事实上,Android系统中的任务更多的是体现是应用程序运行的时候,因此,它相对于Activity来说是动态存在的,这就是为什么我们在开发时对任务这个概念不是那么直观的原因。不过,我们在开发Android应用程序时,还是可以配置Activity的任务属性的,即告诉系统,它是要在新的任务中启动呢,还是在已有的任务中启动,亦或是其它的Activity能不能与它共享同一个任务,具体配置请参考官方文档:它是这样介绍以singleTask方式启动的Activity的:Thesystemcreatesanewtaskandinstantiatestheactivityattherootofthenewtask.However,ifaninstanceoftheactivityalreadyexistsinaseparatetask,thesystemroutestheintenttotheexistinginstancethroughacalltoitsonNewIntent()method,ratherthancreatinganewinstance.Onlyoneinstanceoftheactivitycanexistatatime.它明确说明,以singleTask方式启动的Activity,全局只有唯一个实例存在,因此,当我们第一次启动这个Activity时,系统便会创建一个新的任务,并且初始化一个这样的Activity的实例,放在新任务的底部,如果下次再启动这个Activity时,系统发现已经存在这样的Activity实例,就会调用这个Activity实例的onNewIntent成员函数,从而把它激活起来。从这句话就可以推断出,以singleTask方式启动的Activity总是属于一个任务的根Activity。但是文档接着举例子说明,当用户按下键盘上的Back键时,如果此时在前台中运行的任务堆栈顶端是一个singleTask的Activity,系统会回到当前任务的下一个Activity中去,而不是回到前一个Activity中去,如下图所示:真是坑爹啊!有木有!前面刚说singleTask会在新的任务中运行,并且位于任务堆栈的底部,这里在TaskB中,一个赤裸裸的带着singleTask标签的箭头无情地指向TaskB堆栈顶端的ActivityY,刚转身就翻脸不认人了呢!狮屎胜于熊便,我们来做一个实验吧,看看到底在启动这个singleTask的Activity的时候,它是位于新任务堆栈的底部呢,还是在已有任务的顶部。首先在Android源代码工程中创建一个Android应用程序工程,名字就称为Task吧。关于如何获得Android源代码工程,请参考在Ubuntu上下载、编译和安装Android最新源代码一文;关于如何在Android源代码工程中创建应用程序工程,请参考在Ubuntu上为Android系统内置Java应用程序测试ApplicationFrameworks层的硬件服务一文。这个应用程序工程定义了一个名为shy.luo.task的package,这个例子的源代码主要就是实现在这里了。下面,将会逐一介绍这个package里面的文件。应用程序的默认Activity定义在src/shy/luo/task/MainActivity.java文件中:viewplain1.packageshy.luo.task;2.3.importandroid.app.Activity;4.importandroid.content.Intent;5.importandroid.os.Bundle;6.importandroid.util.Log;7.importandroid.view.View;8.importandroid.view.View.OnClickListener;9.importandroid.widget.Button;10.11.publicclassMainActivityextendsActivityimplementsOnClickListener{12.privatefinalstaticStringLOG_TAG=shy.luo.task.MainActivity;13.14.privateButtonstartButton=null;15.16.@Override17.publicvoidonCreate(BundlesavedInstanceState){18.super.onCreate(savedInstanceState);19.setContentView(R.layout.main);20.21.startButton=(Button)findViewById(R.id.button_start);22.startButton.setOnClickListener(this);23.24.Log.i(LOG_TAG,MainActivityCreated.);25.}26.27.@Override28.publicvoidonClick(Viewv){29.if(v.equals(startButton)){30.Intentintent=newIntent(shy.luo.task.subactivity);31.startActivity(intent);32.}33.}34.}它的实现很简单,当点击它上面的一个按钮的时候,就会启动另外一个名字为“shy.luo.task.subactivity”的Actvity。名字为“shy.luo.task.subactivity”的Actvity实现在src/shy/luo/task/SubActivity.java文件中:viewplain1.packageshy.luo.task;2.3.importandroid.app.Activity;4.importandroid.os.Bundle;5.importandroid.util.Log;6.importandroid.view.View;7.importandroid.view.View.OnClickListener;8.importandroid.widget.Button;9.10.publicclassSubActivityextendsActivityimplementsOnClickListener{11.privatefinalstaticStringLOG_TAG=shy.luo.task.SubActivity;12.13.privateButtonfinishButton=null;14.15.@Override16.publicvoidonCreate(BundlesavedInstanceState){17.super.onCreate(savedInstanceState);18.setContentView(R.layout.sub);19.20.finishButton=(Button)findViewById(R.id.button_finish);21.finishButton.setOnClickListener(this);22.23.Log.i(LOG_TAG,SubActivityCreated.);24.}25.26.@Override27.publicvoidonClick(Viewv){28.if(v.equals(finishButton)){29.finish();30.}31.}32.}它的实现也很简单,当点击上面的一个铵钮的时候,就结束自己,回到前面一个Activity中去。再来看一下应用程序的配置文件AndroidManifest.xml:viewplain1.?xmlversion=1.0encoding=utf-8?2.manifestxmlns:android==shy.luo.task4.android:versionCode=15.android:versionName=1.06.applicationandroid:icon=@drawable/iconandroid:label=@string/app_name7.activityandroid:name=.MainActivity8.android:label=@string/app_name9.intent-filter10.actionandroid:name=android.intent.action.MAIN/11.categoryandroid:name=android.intent.category.LAUNCHER/12./intent-filter13./activity14.activityandroid:name=.SubActivity15.android:label=@string/sub_activity16.android:launchMode=singleTask17.intent-filter18.actionandroid:name=shy.luo.task.subactivity/19.categoryandroid:name=android.intent.category.DEFAULT/20./intent-filter21./activity22./application23./manifest注意,这里的SubActivity的launchMode属性配置为singleTask。再来看界面配置文件,它们定义在res/layout目录中,main.xml文件对应MainActivity的界面:viewplain1.?xmlversion=1.0encoding=utf-8?2.LinearLayoutxmlns:android=:orientation=vertical4.android:layout_width=fill_parent5.android:layout_height=fill_parent6.android:gravity=center7.Button8.android:id=@+id/button_start9.android:layout_width=wrap_content10.android:layout_height=wrap_content11.android:gravity=center12.android:text=@string/