- 浏览: 635542 次
- 性别:
- 来自: 杭州
文章分类
最新评论
-
luo_ganlin:
别的不多说,点个赞!
关于Android隐式启动Activity -
IWSo:
谢楼主!研究了好久,原来是这样!
android中如何让LinearLayout实现点击时背景图片切换 -
fantao005x:
粘帖的不错
android中如何让listview的内容全部显示出来 -
learner576539763:
Android_gqs 写道请问博主,Viewstub 可实现 ...
android中ViewStub使用 -
goontosoon:
抄的什么啊,狗屁不通
对ContentProvider中getType(Uri uri)
Activity的加载模式
在上一文中,我们说过,Activity就相当于一块块的七巧板,每个应用用这一个个七巧板组合成了美丽的图画,并用代码验证了每个Activity的生命周期。
那么,每个应用又是如何将各个Activity组合起来的呢?这就是本文要讲的内容。
通常情况下,一个应用有一个Task,这个Task就是为了完成某个工作的一系列Activity的集合。而这些Activity又被组织成了堆栈的形式。
当一个Activity启动时,就会把它压入该Task的堆栈,而当用户在该Activity中按返回键,或者代码中finish掉时,就会将它从该Task的堆栈中弹出。如果我们没有特别的需求,我们的应用就会呈现出如下图所示的情形(好吧,我承认这个图是document里的):
然而,事实上我们的需求远没有我们想的那么简单。有时候,你可能希望在开启一个Activity时,重新开启一个Task;有时你可能希望将已经存在的一个Activity放到栈顶,而不是重新创建一个...
Android为了使我们能够打破默认的堆栈的先后出的模式,提供了两个种方式:一种是在AndroidManifest.xml定义Activity时指定它的加载模式,另一种是在用Intent开启一个Activity时,在Intent中加入标志。如果两种方式都用了,则后者的优先级更高。
两种方式的差别在于,前者在于描述自己,向别的Acttivity等声明你们如何来加载我;而后者则是动态的,指出我要求你(要启动的Activity)如何来加载。本文的重点在于研究在AndroidManifest.xml中声明加载模式。
Android为我们定义了四种加载模式,分别是:standard、singleTop、singleTask和singleInstance。
“拿来主义”——standard模式
我们写一段代码来测试一下standard加载模式,如下
AndroidManifest.xml里Activity的设置如下:
1. <activity android:name=".Activity1"
2. android:launchMode="standard"
3. android:label="@string/app_name">
4. <intent-filter>
5. <action android:name="android.intent.action.MAIN" />
6. <category android:name="android.intent.category.LAUNCHER" />
7. </intent-filter>
8. </activity>
Activity1的代码如下:
1. public class Activity1 extends Activity {
2. @Override
3. public void onCreate(Bundle savedInstanceState) {
4. super.onCreate(savedInstanceState);
5. setContentView(R.layout.main);
6. }
7.
8. /**当点击Activity时,启动另一个Activity1*/
9. @Override
10. public boolean onTouchEvent(MotionEvent event) {
11. Intent intent = new Intent(this, Activity1.class);
12. startActivity(intent);
13. return super.onTouchEvent(event);
14. }
15.}
然后我们启动程序,开启Activity1,然后点击Acitivity1,启动另一个Activity1,然后再点击,再点击,再点击... 之后我们点返回键。
发生了什么事情?没错,我们按返回键返回一个又一个相同的Activity1。
standard是Activity默认的加载模式,这种方式用一个词来形容的话就是“拿来主义”。使用这种模式的Activity向所有使用它的Task声明:“我这里的这种Activity多着呢,谁需要的话我就给谁”。所以当一个Task请求加载这个Activity时,该Task直接实例化该Activity,并把它放到栈顶。
因此我们的例子就出现了这样的堆栈结构(假设我们点击了4次):
Activity1 |
Activity1 |
Activity1 |
Activity1 |
Activity1 |
我们设想一个情形:我们要做一个图片浏览器,第一个界面是图片列表界面(假设为PictureListActivity),第二个界面是浏览该张图片(假设为PictureViewActivity)。在PictureViewActivity中可以startActivity启动浏览界面浏览上一张和下一张。
如果每一张图片的浏览启动一个PictureViewActivity(当然你可能不是采用这种方式来浏览上一张和下一张,这里只是举个例子),如果采用standard模式的话,就会出现多个PictureViewActivity在堆栈中堆叠的情形。下面介绍的singleTop便可以解决这个问题。
“拒绝堆叠”——singleTop模式
我们将上面的例子稍加改动,AndroidManifest.xml中Acitivity1的launchMode改为singleTop,Activity1的代码修改如下:
1. public class Activity1 extends Activity {
2. @Override
3. public void onCreate(Bundle savedInstanceState) {
4. super.onCreate(savedInstanceState);
5. setContentView(R.layout.main);
6. //Activity1创建时显示Toast
7. Toast.makeText(this, "onCreate called!", Toast.LENGTH_SHORT).show();
8. }
9.
10. @Override
11. protected void onNewIntent(Intent intent) {
12. setTitle("I am Activity1 too, but I called onNewIntent!");
13. super.onNewIntent(intent);
14. }
15.
16. //点击进入加载Activity1
17. @Override
18. public boolean onTouchEvent(MotionEvent event) {
19. Intent intent = new Intent(this, Activity1.class);
20. startActivity(intent);
21. return super.onTouchEvent(event);
22. }
23.}
同样,我们启动程序,开启Activity1,然后点击Acitivity1,启动另一个Activity1,然后再点击,再点击,再点击... 之后我们点返回键。
结果,Activity1第一次创建时,显示一个Toast提示,onCreate被调用,当再次点击时,onCreate没有被调用相反是进入了onNewIntent函数。当按返回键时,直接退出了该应用,可见,堆栈中只存在一个Acitivity1。
可见,当activity被设置为singleTop的加载模式时,如果堆栈的顶部已经存在了该Activity,那么,它便不会重新创建,而是调用onNewIntent。如果,该Activity存在,但不是在顶部,那么该Activity依然要重新创建,请读者自行验证。
因此singleTop模式的思想便是“拒绝堆叠”!
以上说的两种加载模式,Activity均可以实例化多次,而下面讲的两个加载模式就只可以实例化一次。
“独立门户”——singleTask模式
我们首先测试一下,在本应用内调用singleTask模式的Activity会出现什么情况。
我们写两个Activity(Activity1和Activity2),相互调用,其中Activity1为singleTask模式。AndroidManifest.xml如下:
1. <application android:icon="@drawable/icon" android:label="@string/app_name">
2. <activity android:name=".Activity1"
3. android:launchMode="singleTask"
4. android:label="@string/app_name">
5. </activity>
6. <activity android:name=".Activity2">
7. <intent-filter>
8. <action android:name="android.intent.action.MAIN" />
9. <category android:name="android.intent.category.LAUNCHER" />
10. </intent-filter>
11. </activity>
12.</application>
两个Activity的代码如下:
/**Activity1的代码*/
1. public class Activity1 extends Activity {
2. private static final String TAG = "Activity1";
3. @Override
4. public void onCreate(Bundle savedInstanceState) {
5. super.onCreate(savedInstanceState);
6. setContentView(R.layout.main);
7. Log.e(TAG, "Activity1 onCreate! HashCode=" + this.hashCode() + " TaskId=" + getTaskId());
8. }
9.
10. @Override
11. protected void onNewIntent(Intent intent) {
12. Log.e(TAG, "Activity1 onNewIntent! HashCode="+ this.hashCode() + " TaskId=" + getTaskId());
13. super.onNewIntent(intent);
14. }
15.
16. @Override
17. protected void onDestroy() {
18. Log.e("Activity1", "Activity1 onDestroy! HashCode="+this.hashCode()+ "TaskId="+getTaskId());
19. super.onDestroy();
20. }
21.
22. /**点击进入Activity2*/
23. @Override
24. public boolean onTouchEvent(MotionEvent event) {
25. Intent intent = new Intent(this, Activity2.class);
26. startActivity(intent);
27. return super.onTouchEvent(event);
28. }
29.}
1. /**Activity2的代码*/
2. public class Activity2 extends Activity {
3. private static final String TAG = "Activity2";
4. @Override
5. protected void onCreate(Bundle savedInstanceState) {
6. super.onCreate(savedInstanceState);
7. setContentView(R.layout.main2);
8. Log.e(TAG, "Activity2 onCreated! HashCode=" + this.hashCode() + " TaskId="+getTaskId());
9. }
10.
11. @Override
12. protected void onDestroy() {
13. Log.e(TAG, "Activity2 onDestroy! HashCode="+this.hashCode()+" TaskId="+getTaskId());
14. super.onDestroy();
15. }
16.
17. /**点击进入Activity1*/
18. @Override
19. public boolean onTouchEvent(MotionEvent event) {
20. Intent intent = new Intent(this, Activity1.class);
21. startActivity(intent);
22. return super.onTouchEvent(event);
23. }
24.}
从代码中我们可以看出,每当两个Activity创建、销毁以及onNewIntent时,都会打印该Activity的HashCode和所在的Task id。
我们的操作步骤是这样的,打开应用程序,默认启动Activity2,点击Activity2,进入Activity1,再点击Activity1进入Activity2,再点击Activity2进入Activity1,然后按返回键,直到返回到Home。
晕了吧,好写个顺序来形象的表示下:Activity2->Activity1(singleTask)->Activity2->Activity1(singleTask)。^_^
进入Activity2,然后到Activity1,我们看Log信息为:
03-01 14:50:08.144: ERROR/Activity2(371): Activity2 onCreated! HashCode=1156067168 TaskId=7
03-01 14:50:13.923: ERROR/Activity1(371): Activity1 onCreate! HashCode=1156107384 TaskId=7
我们看到,当本应用启动singleTask的Activity(Activity1)时,Activity1并没用另外启用一个任务。而是在原来的任务中创建了它。
再从Activity1进入Activity2,然后再进入Activity1,这个过程,我们再看log信息:
03-01 14:53:50.823: ERROR/Activity2(371): Activity2 onCreated! HashCode=1156128904 TaskId=7
03-01 14:53:58.154: ERROR/Activity1(371): Activity1 onNewIntent! HashCode=1156107384 TaskId=7
03-01 14:53:58.394: ERROR/Activity2(371): Activity2 onDestroy! HashCode=1156128904 TaskId=7
从这个Log信息我们可以得到这个结论:当singleTask模式的Activity启动时,如果发现在某个Task中已经存在,那么它会先将该Activity(Activity1)上部的Activity(Activity2)销毁,然后调用它(Activity1)的onNewIntent函数。
我们下面来研究一下当singleTask的Activity被其他应用调用时的情况。
为了使Activity1能够被其他应用程序调用,我们在AndroidManifest.xml中加入action,如下:
1. <activity android:name=".Activity1"
2. android:launchMode="singleTask"
3. android:label="@string/app_name">
4. <intent-filter>
5. <action android:name="com.winuxxan.singleTask" />
6. <category android:name="android.intent.category.DEFAULT" />
7. </intent-filter>
8. </activity>
然后我们另外创建一个工程,创建一个Activity在初始化的时候启动Activity1,代码如下:
1. public class MyActivity extends Activity {
2. @Override
3. public void onCreate(Bundle savedInstanceState) {
4. super.onCreate(savedInstanceState);
5. setContentView(R.layout.main);
6. Log.e("MyActivity", "TaskId=" + getTaskId());
7. Intent intent = new Intent("com.winuxxan.singleTask");
8. startActivity(intent);
9. }
10.}
我们的操作方法是,MyActivity->Activity1->Activity2->Activity1,之后我们按Home键,然后再从Home重新进入MyActivity所在的应用。
首先看MyActivity->Activity1这个过程,我们查看Log信息如下:
03-01 15:04:25.784: ERROR/MyActivity(429): TaskId=9
03-01 15:04:26.244: ERROR/Activity1(401): Activity1 onCreate! HashCode=1156107632 TaskId=10
从这个Log信息我们可以看出:当某个应用调用其他应用里声明的singleTask模式的Activity时,它会重新创建一个Task,然后将该Activity实例化并压入堆栈。
接着我们看Activity1和Activity2的相互切换,log信息如下:
03-01 15:04:47.524: ERROR/Activity2(401): Activity2 onCreated! HashCode=1156128104 TaskId=10
03-01 15:04:50.674: ERROR/Activity1(401): Activity1 onNewIntent! HashCode=1156107632 TaskId=10
03-01 15:04:50.994: ERROR/Activity2(401): Activity2 onDestroy! HashCode=1156128104 TaskId=10
和我们所期望的那样,如果Activity发现已经存在时,会销毁其上的Activity,然后调用onNewIntent。
之后,我们按Home键,返回桌面,然后,再次进入该应用,我们神奇的发现,我们进入的是MyActivity界面,taskId为10的所有Activity不知了踪影!
这是因为,该应用对应的task的id为9,所以,进入后之后MyActivity在该task中,所以最后显示的是MyActivity。我的以上Activity1的代码实际上是不好的习惯,因为Activity1很可能会成为一个孤岛,所以建议,如果该Activity的类型不是LAUNCHER,最好不要设为singleTask。
那么singleTask的这些特性有什么用处?我们举一个例子,浏览器就是一个singleTask的例子,启动一个浏览器,在Android中是一个比较沉重的过程,它需要做很多初始化的工作,并且会有不小的内存开销。如果有多个应用都来请求打开网页,那么系统就不会不堪重负。因此,如果浏览器采用singleTask模式,如果有多个请求打开网页的请求,都会在一个Task中响应,这样就会避免以上的情况。
“孤独寂寞”——singleInstance模式
我们现在来研究最后一个加载模式,singgleInstance,测试很简单,我们只要在singleTask测试的例子中,将Activity1的模式改为singleInstance模式即可。
我们首先进行同一应用内部的测试。
首先Activity2->Activity1,观察log信息:
03-01 15:41:59.283: ERROR/Activity2(488): Activity2 onCreated! HashCode=1156067168 TaskId=12
03-01 15:42:04.103: ERROR/Activity1(488): Activity1 onCreate! HashCode=1156107520 TaskId=13
我们发现,当采用singleInstance模式时,启动时创建了一个新的Task,并将Activity1实例化加入到该Task中。
然后我们Activity1->Activity2->Activity1,观察log信息:
03-01 15:43:52.214: ERROR/Activity2(488): Activity2 onCreated! HashCode=1156127728 TaskId=12
03-01 15:43:56.804: ERROR/Activity1(488): Activity1 onNewIntent! HashCode=1156107520 TaskId=13
我们通过该log信息可以得出结论:singleInstance的Activity(Activity1)不允许其他的Activity(Activity2)加入到自己的Task中,它是的内心容不下另一个人,它是一个孤独寂寞的人。 当Activity1发现已经存在一个Task中包含自己的实例时,它会调用自己的onNewIntent。
然后,我们同样也测试一下,如果其它应用程序调用Activity1会出现什么样的情况:
MyActivity->Activity1, 观察log信息:
03-01 15:50:21.134: ERROR/MyActivity(556): TaskId=16
03-01 15:50:21.484: ERROR/Activity1(534): Activity1 onCreate! HashCode=1156107344 TaskId=17
不出意料,Activity1重新创建了一个Task,并将自己的实例入栈。
Activity1->Activity2->Activity1->Activity2, 我们观察log信息:
03-01 15:50:36.484: ERROR/Activity2(534): Activity2 onCreated! HashCode=1156128056 TaskId=18
03-01 15:50:46.114: ERROR/Activity1(534): Activity1 onNewIntent! HashCode=1156107344 TaskId=17
我们从该过程可以看出:如果从其它应用程序调用singleInstance模式的Activity(Activity1),从该Activity开启其他Activity(Activity2)时,会创建一个新的Task(task id为18的那个),实际上,如果包含该Activity(Activity2)的Task已经运行的话,他会在该运行的Task中重新创建。
OK,上面啰嗦了那么多,如果这部分不是很清楚的人,可能已经头昏脑胀了。那我们总结一下吧,这总该看看了吧。
“拿来主义”standard模式。哪里需要调用我我就去哪里,可以多次实例化,可以几个相同的Activity重叠。
“拒绝堆叠”singleTop模式。可以多次实例化,但是不可以多个相同的Activity重叠,当堆栈的顶部为相同的Activity时,会调用onNewIntent函数。
“独立门户”singleTask模式。同一个应用中调用该Activity时,如果该Activity没有被实例化,会在本应用程序的Task内实例化,如果已经实例化,会将Task中其上的Activity销毁后,调用onNewIntent;其它应用程序调用该Activity时,如果该Activity没有被实例化,会创建新的Task并实例化后入栈,如果已经实例化,会销毁其上的Activity,并调用onNewIntent。一句话,singleTask就是“独立门户”,在自己的Task里,并且启动时不允许其他Activity凌驾于自己之上。
“孤独寂寞”singleInstance模式。加载该Activity时如果没有实例化,他会创建新的Task后,实例化入栈,如果已经存在,直接调用onNewIntent,该Activity的Task中不允许启动其它的Activity,任何从该Activity启动的其他Activity都将被放到其他task中,先检查是否有本应用的task,没有的话就创建。
附:由于android文档中的解释不是很清楚,所以做了上述测试,结论也是根据测试得出的结论,singleTask和singInstance的任务创建还跟taskAffience有关,我们下次再研究。如果有不对的地方请大家赶快指正,以防影响他人。多谢。
B.R
Hongcheng
Confidentiality Notice:
The opinions and views expressed in this e-mail are solely those of the author and do not necessarily represent those of YuHua TelTech and its affiliates. YuHua TelTech is not responsible for any liability or damaged caused by viruses transmitted with this e-mail or its attachments. If this e-mail is not originally intended for you, or received by you in error, do not disclose,duplicate,distribute,or use its content to anyone and delete it immediately. This e-mail may contain information that is legally privileged, confidential,or exempt from disclosure.
本邮件所包含之观点及内容,完全是邮件作者独立意见,不代表禹华通信及其分支机构之立场。禹华通信将不对本邮件有可能包含的病毒所引起的损害承担责任。若您并非收件人或错收本邮件,请勿披露、复制、散布或使用本邮件中的任何信息,并请即刻予以删除。本邮件所包含之内容完全是受法律保护的保密信息,应免予被披露
发表评论
-
EditText软键盘弹出问题解决
2013-02-26 23:10 1462当带有EditView的activity第一次进入时,第一 ... -
android中获取系统相关属性adb
2012-11-15 14:41 21961.查看系统相关属性可以通过: adb shell ... -
Android使用Intent传递复杂参数及复杂参数列表
2012-11-05 17:29 1630刚开始一直纠结于Intent只能put像int, ... -
解决P6200/P6800扩展卡第三方软件不可写的BUG
2012-11-05 17:01 1030从XDA看来的步骤:1. Using a root-e ... -
android 中跟actionbar相关的属性
2012-10-25 17:07 2477android:uiOptions 这个属性用于设置A ... -
source insight使用快捷键
2012-10-25 10:59 1555F5指定行号,实现行跳转,在遇到编译错误的时候,能特 ... -
android中推出应用比较有效率的方法
2012-10-11 16:57 1160添加一个全局变量作为程序退出的标记(boolean类型) ... -
declare-styleable的使用
2012-10-09 13:59 1173declare-styleable的使用 decl ... -
android程序安全的建议
2012-09-29 14:58 5288如果保证自己的 ... -
Java自带的线程池ThreadPoolExecutor详细介绍说明和实例应用
2012-09-29 14:45 1075从 Java 5 开始,Java 提供了自己的线程池。线 ... -
android应用检测更新代码
2012-09-24 17:40 1832JAVA代码: UpdateManager.java ... -
adb命令详解
2012-09-19 15:04 2870Android adb的常用命令略解 Androi ... -
android中屏蔽其它系统按钮的dialog
2012-09-18 10:13 1647public class MyProgress ... -
如何给Scrollview里内容截屏并生成bitmap,注意:Scrollview里面内容较多有滚动了
2012-09-18 10:07 1645使用for循环递归累加其内部的子控件的高度: p ... -
wakelock的使用
2012-09-17 11:44 10080PowerManager.WakerLock是我分析St ... -
启动另外一个apk
2012-09-14 13:16 900这篇博文主要是获取其他apk程序的启动的主intent, ... -
android中全屏的方法
2012-09-14 13:04 9631.直接代码编写 @Override ... -
android:installLocation简析
2012-09-12 15:25 1113在Froyo(android 2.2,API Le ... -
外部apk启动启动另外一个apk
2012-09-06 17:54 1050public class TestingBroadc ... -
listview如何实现圆角
2012-09-05 17:32 1937首先呢,我们还是看几个示图:(这是360推出的一款天气预 ...
相关推荐
综上所述,掌握Activity启动模式是Android开发中的重要技能,可以根据实际需求选择合适的模式,提升应用性能和用户体验。"Activity启动模式demo"这个实例提供了一个很好的学习平台,通过实践操作加深理解。
标准模式是最常见的Activity启动模式,每个启动请求都会创建一个新的Activity实例。如果新的实例被叠加到栈顶,那么它会覆盖之前显示的Activity。这种模式适用于大部分Activity,因为它允许灵活的导航和回退操作,...
了解和掌握不同的Activity启动模式对于优化应用程序的行为至关重要。本文将详细讲解四种主要的Activity启动模式:standard、singleTop、singleTask以及singleInstance,并通过实际案例分析它们的应用场景。 1. ...
一、Activity启动模式概述 1. **标准模式(Standard)**:这是Activity的默认启动模式,每次启动都会创建一个新的实例,无论是否已在栈中存在。因此,同一个Activity可能会有多个实例。 2. **单实例模式...
标准模式是最常见的Activity启动模式,每个启动请求都会创建一个新的Activity实例。如果新的实例被压入到栈顶,那么就会出现多个相同实例的情况。这种模式适用于大多数Activity,因为它们通常不需要特殊的行为管理...
在Android应用开发中,Activity的启动模式是决定其如何被创建和管理的关键因素。Activity有四种启动模式:标准模式(standard)、单顶模式(singleTop)、单任务模式(singleTask)和单实例模式(singleInstance)。...
理解Activity的生命周期和启动模式对于开发高效、稳定的应用至关重要。让我们深入探讨Activity的7大生命周期以及4种启动模式。 **Activity生命周期** Activity的生命周期包括了从创建到销毁的各个阶段,主要有以下...
在Android应用开发中,Activity是用户界面的基本组件,它的启动模式是决定Activity如何启动和管理的关键因素。了解和掌握Activity的四种启动模式对于优化用户体验和应用性能至关重要。 1. **standard模式** 这是最...
这是最严格的启动模式,它不仅要求Activity在单独的任务栈中,而且这个任务栈只能包含该Activity的一个实例。这意味着,无论从哪个位置启动该Activity,它始终是任务栈中的唯一成员,所有其他启动的Activity都将被放...
在单任务模式中,Activity总是位于它自己的任务栈中。首次启动时,系统会创建新的任务栈并将Activity压入栈底。之后,任何对这个Activity的启动请求都将检查它是否已经在当前任务栈中,如果在,则会通过调用...
本示例项目“Android中Activity启动模式demo”旨在帮助开发者深入理解Activity的不同启动模式,以便更好地控制应用的行为和流程。Activity有四种基本的启动模式:标准模式(Standard)、单实例模式(SingleInstance...
本节课程内容:Activity启动模式与跳转 Android中采用任务栈的形式来管Activity。栈是一种“先进后出”的数据结构。 Android中的任务栈 Task Stack in Android Activity的启动模式 Activity startup mode Activity...
本示例项目"Activity启动模式实例"深入探讨了四种主要的Activity启动模式:标准模式(Standard)、单实例模式(SingleInstance)、单任务模式(SingleTask)和单栈顶模式(SingleTop)。以下是对这四种启动模式的...
笔者近期做的一个项目用到了Activity的启动模式,也算是第一次深刻地领会到了其强大与方便。在此也是将自己所得与大家分享,自己写了一个比较简易的demo,便于让大家理解。 此篇博客意在让对启动模式不了解的开发者...
在示例代码中,singleInstance和LaunchMode目录可能分别包含了展示不同启动模式的Activity源码。通过这些代码,你可以看到如何设置Activity的launchMode属性,以及在不同模式下启动Activity时的行为差异。理解并掌握...
在Android应用开发中,Activity是用户界面的基本组件,它的启动模式是开发者必须了解的重要概念。本文将深入探讨Android中Activity的四种启动模式:标准模式(Standard)、单实例模式(SingleInstance)、单任务模式...
Activity的启动模式是Android系统管理Activity实例的重要方式,它决定了Activity如何被创建、如何在任务栈中组织以及如何响应用户的操作。本篇文章将深入探讨Activity的四种启动模式:标准模式(Standard)、单实例...