现在的位置: 首页 > 综合 > 正文

解开Android应用程序组件Activity的”singleTask”之谜

2013年12月07日 ⁄ 综合 ⁄ 共 4863字 ⁄ 字号 评论关闭

      在Android应用程序中,可以配置Activity以四种方式来启动,其中最令人迷惑的就是"singleTask"这种方式了,官方文档称以这种方式启动的Activity总是属于一个任务的根Activity。果真如此吗?本文将为你解开Activity的"singleTask"之谜。

        在解开这个谜之前,我们先来简单了解一下在Android应用程序中,任务(Task)是个什么样的概念。我们知道,Activity是Android应用程序的基础组件之一,在应用程序运行时,每一个Activity代表一个用户操作。用户为了完成某个功能而执行的一系列操作就形成了一个Activity序列,这个序列在Android应用程序中就称之为任务,它是从用户体验的角度出发,把一组相关的Activity组织在一起而抽象出来的概念。

        对初学者来说,在开发Android应用程序时,对任务的概念可能不是那么的直观,一般我们只关注如何实现应用程序中的每一个Activity。事实上,Android系统中的任务更多的是体现是应用程序运行的时候,因此,它相对于Activity来说是动态存在的,这就是为什么我们在开发时对任务这个概念不是那么直观的原因。不过,我们在开发Android应用程序时,还是可以配置Activity的任务属性的,即告诉系统,它是要在新的任务中启动呢,还是在已有的任务中启动,亦或是其它的Activity能不能与它共享同一个任务,具体配置请参考官方文档:

       http://developer.android.com/guide/topics/fundamentals/tasks-and-back-stack.html

       它是这样介绍以"singleTask"方式启动的Activity的:

       The system creates a new task and instantiates the activity at the root of the new task. However, if an instance of the activity already exists in a separate task, the system routes the intent to the existing instance through a call to its onNewIntent()
method, rather than creating a new instance. Only one instance of the activity can exist at a time.

       它明确说明,以"singleTask"方式启动的Activity,全局只有唯一个实例存在,因此,当我们第一次启动这个Activity时,系统便会创建一个新的任务,并且初始化一个这样的Activity的实例,放在新任务的底部,如果下次再启动这个Activity时,系统发现已经存在这样的Activity实例,就会调用这个Activity实例的onNewIntent成员函数,从而把它激活起来。从这句话就可以推断出,以"singleTask"方式启动的Activity总是属于一个任务的根Activity。

       但是文档接着举例子说明,当用户按下键盘上的Back键时,如果此时在前台中运行的任务堆栈顶端是一个"singleTask"的Activity,系统会回到当前任务的下一个Activity中去,而不是回到前一个Activity中去,如下图所示:

        真是坑爹啊!有木有!前面刚说"singleTask"会在新的任务中运行,并且位于任务堆栈的底部,这里在Task B中,一个赤裸裸的带着"singleTask"标签的箭头无情地指向Task B堆栈顶端的Activity Y,刚转身就翻脸不认人了呢!

        狮屎胜于熊便,我们来做一个实验吧,看看到底在启动这个"singleTask"的Activity的时候,它是位于新任务堆栈的底部呢,还是在已有任务的顶部。

        首先在Android源代码工程中创建一个Android应用程序工程,名字就称为Task吧。关于如何获得Android源代码工程,请参考在Ubuntu上下载、编译和安装Android最新源代码一文;关于如何在Android源代码工程中创建应用程序工程,请参考在Ubuntu上为Android系统内置Java应用程序测试Application
Frameworks层的硬件服务
一文。这个应用程序工程定义了一个名为shy.luo.task的package,这个例子的源代码主要就是实现在这里了。下面,将会逐一介绍这个package里面的文件。

        应用程序的默认Activity定义在src/shy/luo/task/MainActivity.java文件中:

[java] view
plain
copy

  1. package shy.luo.task;     
  2.     
  3. import android.app.Activity;    
  4. import android.content.Intent;    
  5. import android.os.Bundle;    
  6. import android.util.Log;    
  7. import android.view.View;    
  8. import android.view.View.OnClickListener;    
  9. import android.widget.Button;    
  10.     
  11. public class MainActivity extends Activity  implements OnClickListener {    
  12.     private final static String LOG_TAG = "shy.luo.task.MainActivity";    
  13.     
  14.     private Button startButton = null;    
  15.     
  16.     @Override    
  17.     public void onCreate(Bundle savedInstanceState) {    
  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, "Main Activity Created.");    
  25.     }    
  26.     
  27.     @Override    
  28.     public void onClick(View v) {    
  29.         if(v.equals(startButton)) {    
  30.             Intent intent = new Intent("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文件中:

[java] view
plain
copy

  1. package shy.luo.task;    
  2.     
  3. import android.app.Activity;    
  4. import android.os.Bundle;    
  5. import android.util.Log;    
  6. import android.view.View;    
  7. import android.view.View.OnClickListener;    
  8. import android.widget.Button;    
  9.     
  10. public class SubActivity extends Activity implements OnClickListener {    
  11.     private final static String LOG_TAG = "shy.luo.task.SubActivity";    
  12.     
  13.     private Button finishButton = null;    
  14.     
  15.     @Override    
  16.     public void onCreate(Bundle savedInstanceState) {    
  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, "Sub Activity Created.");    
  24.     }    
  25.     
  26.     @Override    
  27.     public void onClick(View v) {    
  28.         if(v.equals(finishButton)) {    
  29.             finish();    
  30.         }    
  31.     }    
  32. }    

        它的实现也很简单,当点击上面的一个铵钮的时候,就结束自己,回到前面一个Activity中去。

        再来看一下应用程序的配置文件AndroidManifest.xml:

[html] view
plain
copy

  1. <?xml version="1.0" encoding="utf-8"?>    
  2. <manifest xmlns:android="http://schemas.android.com/apk/res/android"    
  3.     package="shy.luo.task"    
  4.     android:versionCode="1"    
  5.     android:versionName="1.0">    
  6.     <application android:icon="@drawable/icon" android:label="@string/app_name">    
  7.         <activity android:name=".MainActivity"    
  8.                   android:label="@string/app_name">    
  9.             <intent-filter>    
  10.                 <action android:name="android.intent.action.MAIN" />    
  11.                 <category android:name="android.intent.category.LAUNCHER" />    
  12.             </intent-filter

抱歉!评论已关闭.