今天带着个人疑问与实际项目开发中遇到的问题,跟大家一起学习下安卓活动与任务堆栈方面的知识,直入正题:相信大家都碰到过并没有过多的操作内存但应用自动强制退出或OOM的吧?这个问题也是我本人在面试过程中被人问到的,顺带学习并记录在博客中,跟大家交流,共同提高改进…说到堆栈,我的第一反应是跟我没关系,操作不到这个吧?其实错了,请大家继续看下文:
如果你的应用中涉及到的东西比较耗内存的话,比如:相机、第三方地图、腾讯、新浪、录音、视频播放、大量图片时,如果这些东西同时存在于应用中时,会有很多奇怪的问题出现,自动退出还不报错等等一系列的问题,还有,如果我们的应用中使用startActivity()过多而且并没有及时finish()掉的话,也会出现这样那样的问题,比如:退出应用时没有退出干净,或者莫名其妙的报OOM,启动的服务自动挂起什么的!
其实,Google已经提供了一套完整的机制让开发人员控制活动栈与任务栈,结合如下代码:(我会以最简单的代码来说明实际开发中遇到的问题处理,不足之外,请大家直接指出批评,有错必改!)
首先:我们来启动三个Activity来模拟生成活动与任务堆栈,三个Activity分别是:AndroidStackTaskActivity1、AndroidStackTaskActivity2、AndroidStackTaskActivity3,具体代码如果下:
- package com.xiaoma.www;
- import android.app.Activity;
- import android.content.Intent;
- import android.os.Bundle;
- import android.view.View;
- import android.view.View.OnClickListener;
- import android.widget.Button;
- /**
- * @Title: AndroidStackTaskActivity.java
- * @Package com.xiaoma.www
- * @Description: 活动、任务堆栈学习
- * @author XiaoMa
- */
- public class AndroidStackTaskActivity1 extends Activity implements OnClickListener{
- private Button next = null ;
- /** Called when the activity is first created. */
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- init();
- }
- private void init(){
- next = (Button)findViewById(R.id.button1);
- next.setOnClickListener(this);
- }
- @Override
- public void onClick(View v) {
- // TODO Auto-generated method stub
- Intent i = new Intent(this,AndroidStackTaskActivity2.class);
- startActivity(i);
- }
- }
- package com.xiaoma.www;
- import android.app.Activity;
- import android.content.Intent;
- import android.os.Bundle;
- import android.view.View;
- import android.view.View.OnClickListener;
- import android.widget.Button;
- /**
- * @Title: AndroidStackTaskActivity2.java
- * @Package com.xiaoma.www
- * @Description: 活动、任务堆栈学习
- * @author XiaoMa
- */
- public class AndroidStackTaskActivity2 extends Activity implements OnClickListener {
- private Button next = null ;
- /** Called when the activity is first created. */
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main2);
- init();
- }
- private void init(){
- next = (Button)findViewById(R.id.button1);
- next.setOnClickListener(this);
- }
- @Override
- public void onClick(View v) {
- // TODO Auto-generated method stub
- Intent i = new Intent(this,AndroidStackTaskActivity3.class);
- startActivity(i);
- }
- }
- package com.xiaoma.www;
- import android.app.Activity;
- import android.content.Intent;
- import android.os.Bundle;
- import android.view.View;
- import android.view.View.OnClickListener;
- import android.widget.Button;
- /**
- * @Title: AndroidStackTaskActivity2.java
- * @Package com.xiaoma.www
- * @Description: 活动、任务堆栈学习
- * @author XiaoMa
- */
- public class AndroidStackTaskActivity3 extends Activity implements OnClickListener {
- private Button next = null ;
- /** Called when the activity is first created. */
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main2);
- init();
- }
- private void init(){
- next = (Button)findViewById(R.id.button1);
- next.setOnClickListener(this);
- }
- @Override
- public void onClick(View v) {
- // TODO Auto-generated method stub
- Intent i = new Intent(this,AndroidStackTaskActivity3.class);
- startActivity(i);
- }
- }
代码很简单, 大家不用看运行效果也可以想出什么情况 ,不过这个地方主要看堆栈,不看这些代码,贴在这里供大家搞清楚三个Activity的启动顺序,此时,生成的活动堆栈如下图所示:
这个地方说明下,有时候大家可以想着从1到2时可以绑定数据完成回显,但是如果要简单的回显用绑定或startActivityForResult()这两种方式启动,但是如果涉及到三个以上的活动惑更多活动之间的跳转时,有时候不得不必须重新启动新的活动,也就出现了前面的1>>2>>3>>4>>>>>>>甚至更多的活动跳转,这样一个个关闭有时候还是关不干净,应用退出的时候也还是不干净的,更搞笑的是有时候还有用户在多个活动之间跳转并不进行任何数据操作时还要求返回上一个Activity时你就不能直接finish掉上一个Activity,不然人家说你跳转不对,针对这个问题我们来看下Google提供的堆栈任务控制机制吧,很简单,用Flag来控制,这个时候就有个问题,提供的方法有setFlag()、addFlag(),这两个肯定有什么区别的,不然不会出现两个控制Flag的方法的,继续….先看下如下两种效果:
第一种:未设置Flag时
第二种 :已设置Flag时
如上所示,大家应该看出来了,同样点击了六次按钮之后按的返回键,第一种效果必须点击六次Back键后方可退出,而第二种效果只点击一次即可退出,这就是Flag的魅力,激动….再来看Flag都有哪几种吧,此处我列在这个地方,上面两个效果中设置的是:i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);另外还有很多可以控制活动堆栈与任务栈的Flag,小马在这个地方随便列出两个,剩余的Flag值以截图的形式显示,节约时间:
1. i.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
2. i.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY)其它:
大家可以很清楚的看到以后所含的标志中有针对于TASK的,对吧?指的就是任务堆栈,至于什么是任务堆栈,大家不用太过纠结于与活动堆栈之间的概念什么的,只记住一点:如果你在应用中启动Activity的时候没加任务堆栈的控制Flag时,开发环境肯定报错,而且提示的很准确 ,就是:你缺少添加任务堆栈Flag标志位,具体少了哪个标志,开发环境也会很准确的指出,必须要你添加才可正常编译通过!下面列下小马犯的错误,就是在一个Activity找到一个amr录音文件,直接以下面的方式启动去播放录音,猛报错:
- Intent i = new Intent(Intent.ACTION_VIEW);
- i.putExtra("filePath",path);
- startActivity(i);
如果加了 i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);操作下任务堆栈就可以了,具体的原因,也可以用一句话来总结:如果在一个Activity中同一时间,要操作不用的功能,比如:跳转时还要操作视频录音文件的播放什么的,都得设置新的任务栈来启动打开,如果不启动新任务栈的话,有时候会无原无故的显示空白还不报错!上面的错只是一个小点,小到可以忽略不讲,写在这是提醒大家,该加的时候必须加Flag,至于什么时候加,大家可以参照下官方的文档及下面小马贴出的官方文档中解释堆栈的图解,加以理解学习,如下所示:
Figure2:不多解释,就是在A B 丙个任务堆栈,如果用户正在于B任务堆栈进行交互时,A在等待唤醒,反之则反
Figure3: 下面这个就好玩了,学习了下官方的文档,讲的是:无论启动了一个新的任务堆栈或者在同一堆栈中来启动一个活动,按返回键也还是会返回到用户之前操作的Activity,如果以单例堆栈(类似单位模式)载入的话,就会在后台生成一个针对于此活动的单独的一个任务堆栈,当这个任务堆栈被唤醒到前台时,此时的返回堆栈中就包含了从前几个任务传递过来的栈顶的所有Activity,栈顶与栈底的显示关系如果下图:
这个地方顺带着讲下,在控制活动堆栈时方式只有一种,就是直接在.java文件中setFlag,如果是控制任务堆栈的话可以以addFlag或直接在全局配置文件中添加配置的方式来控制,大家可以直接在AndroidManifest.xml文件中activity节点中添加哪下属性:taskAffinity、launchMode、allowTaskReparenting、clearTaskOnLaunch、alwaysRetainTaskState、finishOnTaskLaunch,两种控制任务堆栈的方式换汤不换药,大家看个人习惯选择使用就可以了…切记,用的时候一定搞清楚你要加的标志位是什么意思,不要看到个task就addFlag,设置Flag是为了让应用更干净,控制更严密,如果加错了标志位,应用是不会报任何错的,只是出现怪异的跳转与关闭!!!这是我个人乱加Flag时的教训,大家也谨用!今天就先写到这啦,文章中难免会有不尽人意之处,若有疑问有错误,请大家直接指出批评!
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。