放牧代码和思想
专注自然语言处理、机器学习算法
    愛しさ 優しさ すべて投げ出してもいい

解决Theme.Translucent 下 FLAG_ACTIVITY_REORDER_TO_FRONT 的问题

为了复用Activity,我将项目里所有的Activity在启动时加上了FLAG_ACTIVITY_REORDER_TO_FRONT,后来由于美观的需求,将所有Activity的Theme加上了<item name="android:windowIsTranslucent">true</item>,结果惊讶地发现FLAG_ACTIVITY_REORDER_TO_FRONT失效了。

当我用FLAG_ACTIVITY_REORDER_TO_FRONT reoder一个Activity到栈顶的时候,发现该Activity的onResume的确调用了,但是就是没有显示在屏幕上。

我对FLAG_ACTIVITY_REORDER_TO_FRONT的理解是这样的:

/**
             * Intent.FLAG_ACTIVITY_REORDER_TO_FRONT这个标志表示:
             * 如果这个activity已经启动了,就不产生新的activity,
             * 而只是把这个activity实例加到栈顶来就可以了。
             * 会触发onResume事件
             */

后来一番Google,发现还真有人跟我遇到了一样的问题,StackOverflow上的同僚把它称为Bug:http://stackoverflow.com/questions/9309479/bug-theme-translucent-flag-activity-reorder-to-front 。从这里我知道去掉android:windowIsTranslucent之后的确一切正常,但是这很明显不是我想要的结果。

在StackOverflow上面的回复中,有人提到将launchMode设为singleInstance即可解决问题。我测试了一下,的确如此,既可以单例又可以透明。然而singleInstance的意思是一个Activity独占一个Task,这也未免太浪费了,于是我改为了singleTask,这样可以节省一些开销。

附录一份launchMode和FLAG的说明复习备用:

我们都知道,通过Intent启动Activity有两种形式:

  1. 显式的指向某个Activity

     Intent intent = new Intent(this, Activity1.class);
     startActivity(intent);

  2. 隐式的通过设置Intent的动作启动Activity

     Intent intent = new Intent(Intent.ACTION_VIEW);
     intent.setData(Uri.parse("http://www.google.com"));
     startActivity(intent);

Activty是Android四大组件中负责与用户交互的部件,Activity承担了大量的显示和交互工作,从某种角度上将,我们看见的应用程序就是许多个Activity的组合。

Task Stack

为了让这许多Activity协同工作而不至于产生混乱,Android平台设计了一种堆栈机制用于管理Activity,其遵循先进后出的原则,系统总是显示位于栈顶的Activity,从逻辑上将,位于栈顶的Activity也就是最后打开的Activity,这也是符合逻辑的。这个栈也可以叫做Task Stack,因为一个Task Stack里的Activity是可以属于不同的Application的。例如:你想在发送短信时,拍一张照并作为彩信发出去,这时你首先停留在短信应用程序的的Acitivity上,然后跳转到Camera应用程序的Activity上,当完成拍照功能后,再返回到短信应用程序的Activity。这实际上是两个Android Application协同合作后完成的工作,但为了更好的用户体验,Android平台加入了Task这么一种机制,让用户没有感觉到应用的中断,让用户感觉在一“应用程序”里就完成了想完成的工作。

值得注意点的时候,一个系统里可以有很多的Task Stack,当后台的Task过多的时候,系统可能会去除栈底的Activity,释放多余的内存。

保存Activity状态

当Task Stack中的Activity返回前台的时候,可能已经是被系统释放点重新创建的,为了用户的操纵信息得到保留,我们最好重写onSaveInstanceState方法。

Managing Tasks

我们在平常写程序的时候,Activity的启动方式保持默认就已经够用了。但是遇到特定场合,我们可以通过对启动方式的更改来修改Activity在Task中的运行状态。

Activity的启动状态我们可以在AndroidManifest.XML中定义,抑或直接通过Intent传相应的数值对。

  • 操作manifest文件,Activity状态设置是其节点launchMode属性定义,共有四种形式:

    1. “standard”
      默认方式,Activity可以创建多次,分布在不同的Task Stack中,有相应不同的实体。

    2. “singleTop”
      通过此方法启动的Activity如果在栈顶的话,当再次收到启动的Intent,将不会再创建新实例,而是直接执行onNewIntent方法。Activity可以有多个实例,在每个Task Stack中除非不在栈顶,在接受到启动的Intent的时候都不会创建新实例。
      比如一个Task Stack:A->B->C->D,如果是Standard模式,当收到D的启动Intent时,Stack:A->B->C->D->D,如果是SingleTop模式,Stack:A->B->C->D。而当收到的是B的启动Itent时,Stack:A->B->C->D->B,因为B不在栈顶。

    3. “singleTask”
      这种模式下,Activity只能存在一个实例,当再次收到启动的Intent时,直接执行onNewIntent方法。

    4. “singleInstance”
      类似于singleTask,不同的地方是,Activity只能有一个实例,而且该实例的Task Stack只能有这个Activity,也就是说通过该模式启动的Activity在Task Stack中即是栈顶也是栈底。

  • Intent通过setFlags或者addFlags方法添加数值对,默认方式是不用做任何操作的,除此之外还有三种形式:

    1. FLAG_ACTIVITY_NEW_TASK
      启动一个新的Task Stack,当包括Activity的Task已经存在的时候,这个Task将会直接在前台显示,类似与singleTask。

    2. FLAG_ACTIVITY_SINGLE_TOP
      当这个Intent启动的前台的Activity,将不会创建新实例,而是直接执行onNewIntent,类似于singleTop。

    3. FLAG_ACTIVITY_CLEAR_TOP
      如果启动的Activity在Task Stack中,其余的Activity都会被弹出释放,不会创建新实例,而是执行onNewIntent

      转自http://kescoode.com/2013/12/04/android%E4%B8%8B%E7%9A%84%E4%BB%BB%E5%8A%A1%E4%B8%8Eactivity%E6%A0%88/


知识共享许可协议 知识共享署名-非商业性使用-相同方式共享码农场 » 解决Theme.Translucent 下 FLAG_ACTIVITY_REORDER_TO_FRONT 的问题

评论 欢迎留言

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

我的作品

HanLP自然语言处理包《自然语言处理入门》