HOME键与Notification配合使用的bug重现【原创】
2011-09-30 17:19
281 查看
[b]前言[/b]
最近几天刚刚跳槽完毕。在家歇了快一个月了。重现开始上班后,还真有点不适应。上班实在是太辛苦了, 还是坐地铁13号线。但是变成反向乘坐了。 昨天才拿到的电脑,连代码还没看呢,就接到了新的任务:解决一个bug。 好了,废话不多说,先描述一下bug情况。
[b]BUG描述[/b]
程序中在某个地方加入一个Notification。把程序全部退出(是finish的那种),用notification来启动程序,进行操作。随便进入了一个页面A,此时点击“home”,然后再长按“HOME”,回到该程序。 结果不能返回到之前的页面A了。
简短分析: 刚开始我认为是程序的问题,加入很多log日志,也没能解决该问题。 最后,我怀疑是android系统的问题。下面我就写了一个简单的代码,来重现该问题。
[b]DEMO实例[/b]
先来个图,看看这个DEMO的演示情况:
结合图像,展示功能列表:
1. 该程序共有3个Activity。分别从title中进行区别:test,test2, test3.
2. 消息栏中有个图片,可以使用该图标来启动程序。程序到达test2.
3. 正常启动程序,到达的activity为test。
4. test和test2的 Activity中,b按钮的功能是掉转到test3.
5. 在test的Activity中,a按钮的功能是生成notification。
代码:
public class TestActivity extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); } public void a(View view) { //启动掉转到Test2 Intent intent = new Intent(TestActivity.this, Test2Activity.class); intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_NEW_TASK); PendingIntent contentIntent = PendingIntent.getActivity(TestActivity.this, 0, intent,PendingIntent.FLAG_UPDATE_CURRENT); Notification notification = new Notification(R.drawable.icon, "ticker", System.currentTimeMillis()); notification.setLatestEventInfo(TestActivity.this, "title", "text", contentIntent); NotificationManager notificationMgr = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); notificationMgr.notify(1000, notification); } public void b(View view) { //掉转到Test3 Intent intent = new Intent(TestActivity.this, Test3Activity.class); startActivity(intent); } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if(keyCode == KeyEvent.KEYCODE_BACK) System.exit(0); return super.onKeyDown(keyCode, event); } }
能靠notification启动的Activity:
public class Test2Activity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); } public void a(View view) {} public void b(View view) { //掉转到Test3 Intent intent = new Intent(Test2Activity.this, Test3Activity.class); startActivity(intent); } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if(keyCode == KeyEvent.KEYCODE_BACK) System.exit(0); return super.onKeyDown(keyCode, event); } }
Test3就没有什么代码可以展示了,就是一个表达的区别页面。
[b]重现操作流程[/b]
1. 启动程序。页面为Test Activity。
2. 点击a按钮,启动一个notification待用。
3. 点击“back”,关闭该程序。
4. 点击notification,启动程序到达Activity Test2.
5. 简介b按钮,跳转页面到TEST3.
6. 点击“HOME”键,回到主界面。
7. 长按“HOME”,尝试回到之前的程序。bug发生(页面没有回到TEST3,而是到达页面TEST2.更让人奇特的是Test3执行力OnDestory方法)
[b]深入分析[/b]
1。 首先要理解activity的launchMode的值。参考文章:http://marshal.easymorse.com/archives/2950。
我的解析: singleTask是用在一个应用中要共享一个activity。他们的taskId与之前是一样的。当被标记为singleTask的应用已经存在时,就直接跳转到该ACT,并清空上面的ACT。
singleInstance是用在多个应用共享一个ACT。也就是该ACT的taskID和之前的是不一样的。并且该ACT的栈中,有且仅有那个一个ACT。
2。 singleTask是否启动新的taskID。
singleTask并不会每次都新启动一个task。如果已经存在一个task与新活动亲和度(taskAffinity)一样,该活动将启动到该task。如果不是,才启动一个新task。
同一个application里面,每个activity的taskAffinity默认都是一样的。也就是说楼主代码里的ActivityTwo和ActivityMain的taskAffinity是一样的,假设这个taskAffinity是"com.test"。ActivityMain启动时,新建了一个task,这个task的taskAffinity就是"com.test"。ActivityTwo具有singleTask属性,启动时,会先寻找是否有相同taskAffinity的task存在,没有的话,才会启动一个新的task,但是这时发现已经有一个task存在了,它的taskAffinity也是"com.test",就不会启动新的task了,而是把ActivityTwo放入这个task的栈中,这时候task id是一样的。
所以使用singleTask时,要想新建一个task,就得保证taskAffinity值不同,比如设置ActivityTwo的taskAffinity="com.test2",这时再运行楼主的代码,就会发现task id不一样了。
以上是两个activity在同一个application中的情况。如果在某个application调用其他application里声明的singleTask模式的Activity呢。taskAffinity的值默认是包名,两个application一般包名都不一样,如果taskAffinity都是默认的话,它会重新创建一个Task,然后将该Activity实例化并压入task的栈。
3。 理解了上面的内容。下面就来点关键的。
在开发者文档中有这样写的内容:
当Intent中包含有Flag_ACTIVITY_NEW_TASK时,
当有了上面那个属性,只有affinity的值与之前的affinity的值不一致,才考虑去new一个新的之。
解决办法:
在其他的程序中加入:intent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT|Intent.FLAG_ACTIVITY_NEW_TASK);
//如果activity在task存在,拿到最顶端,不会启动新的Activity
intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
//如果activity在task存在,将Activity之上的所有Activity结束掉
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
//默认的跳转类型,将Activity放到一个新的Task中
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
//如果Activity已经运行到了Task,再次跳转不会在运行这个Activity
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
相关文章推荐
- [原创]java WEB学习笔记68:Struts2 学习之路-- 类型转换与复杂属性配合使用
- Android 四大组件之(3)BroadcastReceiver广播事件处理以及与Notification的配合使用详解
- [原创]修正SubSonic v2.2.1的一处BUG,以及如何使用SubSonic进行多表查询、子查询以及数据库分页
- (原创)spring mvc和jersey rest 组合使用时单例对像实例化两次的BUG及解决办法
- hadoop-2.2.0配合hive-0.12.0使用orc存储引发的bug
- 关于从状态栏开始布局adjustResize和ScroolView的配合使用不起作用的bug
- 【原创】关于在Objective-C中使用C语言数组的使用和NSArray的差别,以及由此可能产生的一个BUG
- ci框架配合uploadify使用图片上传bug
- 『原创』使用ASP与JAVASCRIPT配合实现多个复选框数据关联显示
- (原创)DataGrid和DropDownList的一些配合以及使用css定制DataGrid
- (原创)DataGrid和DropDownList的一些配合以及使用css定制DataGrid
- [原创]修正SubSonic v2.2.1的一处BUG,以及如何使用SubSonic进行多表查询、子查询以及数据库分页
- 『原创』使用ASP与JAVASCRIPT配合实现多个复选框数据关联显示
- 【正则表达式】使用正则来取html中的正文的bug【原创】
- mousedown和blur配合使用时,ie6/7/8的bug
- XmlPullParser.nextText() bug 好文章,使用pull解析xml注意
- 使用代码检查工具解决C++潜在的bug
- Notification使用详解之二:可更新进度的通知
- 【原创翻译】如何在本地主机上使用tbdev建立一台bt Tracker服务器【网站建设文档】
- 配合Ajaxpro读取无限父子关系部门使用javascript生成的树形目录