你的位置:首页 > Java教程

[Java教程]安卓开发笔记——深入Activity


  在上一篇文章《安卓开发笔记——重识Activity 》中,我们了解了Activity生命周期的执行顺序和一些基本的数据保存操作,但如果只知道这些是对于我们的开发需求来说是远远不够的,今天我们继续探索Activity,来了解下关于Activity任务栈和Activity四种启动模式的区别。

  

在讲Activity任务栈前,我们应该先知道什么是栈?

  简单点来理解,可以把栈比作一个开封的箱子,我们可以往里面塞东西,这里假设塞的东西的底面积和箱子的底面积是相同的,那么这些东西就具备有从下往上一定的顺序,当我们想要取出箱子里面的东西时,我们没有办法一下子拿到箱子最底层的东西,我们只能拿到最上面一层的东西,从上往下。

  来看下这张图,这里的箱子就是栈,箱子口可以看作是栈的入口与出口,东西代表数据。栈的特点:具有一定的次序,后进先出(越先放入的东西,越晚出来)。

1、任务栈  

 好了,在了解了什么是栈之后,我们可以开始进入今天的主题了,在Android的官方文档描述中我们可以知道,任务栈也是栈,具有栈的一切特点。

  Activity任务栈,顾名思义是存放Activity任务的栈,这里的任务栈为上图箱子,Activity为上图的东西。

  当我们每打开一个Activity的时候它会就往Activity任务栈中压入一个Activity,当我们每销毁一个Activity的时候它会从Activity任务栈中弹出一个Activity,由于安卓系统自身的设计,我们只能在手机屏幕上获取当前一个Activity的焦点即栈顶元素(最上面的Activity),其余的Activity会暂居后台等待系统调用。

 

1.1、关于任务栈的概念:

任务栈是用来提升体验而设计的:
(1) 程序打开时就创建了一个任务栈, 用于存储当前程序的activity,当前程序(包括被当前程序所调用的)所有的activity属于一个任务栈。
(2) 一个任务栈包含了一个activity的集合, 可以有序的选择哪一个activity和用户进行交互,只有在任务栈栈顶的activity才可以跟用户进行交互。
(3) 任务栈可以移动到后台,并且保留了每一个activity的状态. 并且有序的给用户列出它们的任务, 而且还不丢失它们状态信息。
(4) 退出应用程序时,当把所有的任务栈中所有的activity清除出栈时,任务栈会被销毁,程序退出。

1.2、关于任务栈的缺点:

(1) 每开启一次页面都会在任务栈中添加一个Activity,而只有任务栈中的Activity全部清除出栈时,任务栈被销毁,程序才会退出,这样就造成了用户体验差,需要点击多次返回才可以把程序退出了。
(2) 每开启一次页面都会在任务栈中添加一个Activity还会造成数据冗余重复数据太多,会导致内存溢出的问题(OOM)。

 

2、Activity的4种启动方式

  为了解决任务栈产生的问题,Android为Activity设计了启动模式,那么下面的内容将介绍Android中Activity的启动模式,这也是最重要的内容之一。

  启动模式(launchMode)在多个Activity跳转的过程中扮演着重要的角色,它可以解决是否生成新的Activity实例,是否重用已经存在的Activity实例,是否和其他实例共用一个任务栈。任务栈是一个具有栈结构的对象,一个任务栈可以管理多个Activity,每启动一个应用,也就创建一个与之对应的任务栈。

  Activity一共有以下四种launchMode模式:1、standard 2、singTop 3、singTask 4、singleInstance,我们可以在AndroidManifest.<activity>的android:launchMode属性为以上四种之一即可。
2.1、实践是检验真理的唯一标准
 下面写个实例,有2个Activity,每个Activity都有一个跳转按钮,第一个Activity点击按钮跳转第二个Activity,第二个Activity点击按钮跳转自身。
 1 package com.lcw.rabbit.activitydemo; 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.widget.Button; 9 10 public class MainActivity extends Activity {11 12   private static final String TAG = "Rabbit";13 14   private Button mbButton;15 16   @Override17   protected void onCreate(Bundle savedInstanceState) {18     super.onCreate(savedInstanceState);19     setContentView(R.layout.activity_main);20 21     Log.i(TAG,"第一个Activity,加入任务栈:"+getTaskId());22 23     //点击按钮跳转第二个Activity24     mbButton = (Button) findViewById(R.id.bt_button);25     mbButton.setOnClickListener(new View.OnClickListener() {26       @Override27       public void onClick(View v) {28         startActivity(new Intent(MainActivity.this, SecondActivity.class));29       }30     });31 32 33   }34 35   @Override36   protected void onDestroy() {37     super.onDestroy();38     Log.i(TAG, "第一个Activity,退出任务栈:" + getTaskId());39   }40 }

MainActivity.java
 1   package com.lcw.rabbit.activitydemo; 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.widget.Button; 9 10   public class SecondActivity extends Activity {11 12     private static final String TAG = "Rabbit";13     private Button mbButton1;14     private Button mbButton2;15 16     @Override17     protected void onCreate(Bundle savedInstanceState) {18       super.onCreate(savedInstanceState);19       setContentView(R.layout.activity_second);20       Log.i(TAG, "第二个Activity,加入任务栈:" + getTaskId());21       //点击按钮跳转第二个Activity22       mbButton1 = (Button) findViewById(R.id.bt_button1);23       mbButton1.setOnClickListener(new View.OnClickListener() {24         @Override25         public void onClick(View v) {26           startActivity(new Intent(SecondActivity.this, MainActivity.class));27         }28       });29       mbButton2 = (Button) findViewById(R.id.bt_button2);30       mbButton2.setOnClickListener(new View.OnClickListener() {31         @Override32         public void onClick(View v) {33           startActivity(new Intent(SecondActivity.this, SecondActivity.class));34         }35       });36     }37 38     @Override39     protected void onDestroy() {40       super.onDestroy();41       Log.i(TAG, "第二个Activity,退出任务栈:" + getTaskId());42     }43   }

SecondActivity.java

  

 

实验一:启动模式standard  

  系统默认的Activity启动模式是standard,我们这里为了检验再设置一下:

 1     <activity 2       android:name=".MainActivity" 3       android:launchMode="standard"> 4       <intent-filter> 5         <action android:name="android.intent.action.MAIN" /> 6         <category android:name="android.intent.category.LAUNCHER" /> 7       </intent-filter> 8     </activity> 9     <activity10       android:name=".SecondActivity"11       android:launchMode="standard"></activity>

  现在我们进入第一个Activity的时候,点击按钮启动第二个Activity,看下当前任务栈:

  当我们点击第二个Activity的按钮,让它跳转自身,看下当前任务栈:

  当我们按下Back键,跳转第一个Activity,销毁第二个Activity时,看下当前任务栈:

  可以发现,这个任务栈和我们刚上图描述的箱子(Activity任务栈)是一致的,从上往下放东西(Activity),越晚放进去的东西(Activity)在越上面,而后面的t1072则代表当前任务栈的编号ID,ID相同代表它们属于同一个任务栈。

  我们从日志文件中也可以看得很清楚:

实验一结论:

  在Activity启动模式为standard(默认)的情况下,不管之前有没有Activity实例,每一次启动Activity都会创建一个新的Activity实例,并置于Activity任务栈栈顶。

 

实验二:启动模式singleTop

 1    <activity 2       android:name=".MainActivity" 3       android:launchMode="standard"> 4       <intent-filter> 5         <action android:name="android.intent.action.MAIN" /> 6         <category android:name="android.intent.category.LAUNCHER" /> 7       </intent-filter> 8     </activity> 9     <activity10       android:name=".SecondActivity"11       android:launchMode="singleTop"></activity>

  现在我们进入第一个Activity点击按钮跳转第二个Activity,然后再点击按钮跳转自身,看下当前任务栈:

  系统日志文件:

  然后我们再点击按钮启动第一个Activity,然后点击按钮启动第二个Activity,看下当前任务栈:

  系统日志:

实验二结论:

  在Activity启动模式为singleTop(栈顶任务唯一)的情况下,如果当前Activity处于栈顶,那么它就不会再去实例化一个新的Activity,当Activity不处于栈顶的时候,会重新实例化一个新的Activity并置于栈顶,此时的任务栈编号为1080。

 

实验三:启动模式singleTask

 1     <activity 2       android:name=".MainActivity" 3       android:launchMode="standard"> 4       <intent-filter> 5         <action android:name="android.intent.action.MAIN" /> 6         <category android:name="android.intent.category.LAUNCHER" /> 7       </intent-filter> 8     </activity> 9     <activity10       android:name=".SecondActivity"11       android:launchMode="singleTask"></activity>

  当我们进入第一个Activity点击进入第二个,再启动自身,看下当前任务栈:

  系统日志:

  现在我们点击启动第一个Activity,再点击启动第二个Activity,看下当前任务栈:

  系统日志:

实验三结论:

  在Activity启动模式为singleTask(唯一实例)的情况下,当启动Activity的时候,如果当前Activity不存在则实例化一个新的Activity,如果当前Activity在任务栈中已经存在,则会复用这个Activity实例,但这边我们从日志打印可以看出在启动第二个Activity的时候,第一个Activity推出了任务栈,也就意味着当启动模式为singTask的时候,启动已经存在在Activity任务栈中但不在栈顶的Activity时,该Activity会把压在它前面的所有Activity弹出任务栈,此时任务栈编号为1081,属于同一个任务栈。

 

实验四:启动模式singleInstance

 1     <activity 2       android:name=".MainActivity" 3       android:launchMode="standard"> 4       <intent-filter> 5         <action android:name="android.intent.action.MAIN" /> 6         <category android:name="android.intent.category.LAUNCHER" /> 7       </intent-filter> 8     </activity> 9     <activity10       android:name=".SecondActivity"11       android:launchMode="singleInstance"></activity>

  现在我们进入第一个Activity点击按钮跳转第二个Activity,再让其跳转自身,看下当前任务栈:

  系统日志:

  现在点击按钮启动第一个Activity,再点击按钮启动第二个Activity,看下当前任务栈:

  系统任务:

  点击Back键,直到程序完全退出,看下系统日志:

 

实验四结论:

  在Activity启动模式为singleInstance的情况下,首先我们可以发现的是启动模式为singleInstance的Activity处于不同的任务栈(Task编号不同),并保证不再有其他的Activity实例进入,它还是和singleTask一样保持唯一实例,然后它的退出顺序是不再是根据调用顺序,而是在不同的任务栈中,从上往下退出。

 

在共用一个Activity实例时,期间发生了什么?

  在上诉模式中,当我们的Activity涉及到同一实例的时候,期间Activity做了哪些事情?在Android官方文档中我们可以知道期间虽然没有新实例化一个Activity,但是调用了onNewIntent方法。

  现在我们在第二个Activity里添加一个onNewIntent方法:

1     @Override2     protected void onNewIntent(Intent intent) {3       super.onNewIntent(intent);4       Log.i(TAG, "第二个Activity,执行onNewIntent");5     }

1、在standard(默认)启动模式下,我们来回的去跳转Activity,看下日志打印,发现是不会调用onNewIntent方法的,因为它不是一个实例。

2、在singleTop模式下,我们从第一个Activity跳转到第二个Activity,再从第二个Activity跳转自身,再跳转第一个Activity,看下日志打印,我们可以发现,当第二个Activity置于栈顶的时候,由于重用了实例,所以调用了onNewIntent方法。

3、当singleTask和singleInstance模式下也是一样的,因为重用了实例,所以会调用onNewIntent方法,且onNewIntent方法是在前一个Activity的onStop方法后(当前ActivityonReStart方法前)立即调用的。

 

好了,今天先写到这里,有什么建议或疑问,可以在文章评论给我留言。

 

作者:李晨玮
出处:http://www.cnblogs.com/lichenwei/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。
正在看本人博客的这位童鞋,我看你气度不凡,谈吐间隐隐有王者之气,日后必有一番作为!旁边有“推荐”二字,你就顺手把它点了吧,相得准,我分文不收;相不准,你也好回来找我!

 




办理日本旅游签证跟团日本旅游需要多少钱几月份去日本旅游最好什么时候去日本旅游最便宜去日本旅游跟团要多少钱洛阳白云山农家宾馆推荐?白云山农家宾馆一晚多少钱? 洛阳白云山景区宾馆介绍?白云山景区宾馆多少钱? 洛阳白云山宾馆哪家好?白云山风景区住宿哪里好? 洛阳白云山农家住宿怎么样?白云山住宿推荐? 香港哪里有影视城吗?具体地址在那里? 去澳门那里买戒指好?澳门有哪些珠宝店? 在澳门葡京娱乐场要门票吗?要的话多少钱? 香港那里有金饰店?香港人给亲人买什么饰品好呢? 马尔代夫最近天气怎么样? 泰国哪个时候最适合旅游?什么时候是最佳的旅游季节? 马尔代夫维斯瑞岛Viceroy Maldives Resort 是最新开发的岛屿吗? 迪拜最近天气怎么样? 深圳小梅沙三八节有什么活动?三八妇女节小梅沙海洋世界活动介绍? 2015三八节小梅沙海洋世界女士免费吗?深圳小梅沙三八妇女节门票价格? 2015三水荷花世界什么时候去最好?3月佛山三水荷花世界有什么花开了? 2015三水荷花世界三八妇女节女士免费吗?佛山三水荷花世界3.8女性门票价格? 08055C153KAZ2A Datasheet 08055C153KAZ2A Datasheet TAJA336K006RNJ Datasheet TAJA336K006RNJ Datasheet TAJA336M006RNJ Datasheet TAJA336M006RNJ Datasheet 鼓浪屿 攻略 鼓浪屿 攻略 鼓浪屿 攻略 台湾土特产 台湾土特产 台湾土特产 广州旅游景点推荐 广州旅游景点推荐 广州旅游景点推荐