令人费解的行为与REORDER_TO_FRONT

活动A开始活动B没有标志。 堆栈现在是AB,B在上面。 B使用FLAG_ACTIVITY_REORDER_TO_FRONT(唯一标志)启动活动A. 我期望堆栈现在是BA。 但是,此时按下后退button时,将返回到主屏幕。 在这里,我期望活动B被带到前面。 再次点击启动器图标,应用程序打开B作为运行活动,没有任何东西在堆栈中。

启动模式是清单中的标准(默认)。

这是预期的行为,我只是不正确的理解?

编辑:我创build了一个没有混淆因素的testing项目,仍然看到相同的行为。 我只是不明白,它似乎不是每个文件。

编辑:对我来说,这个行为似乎是在框架中的一个错误,请参阅我的评论下面的答案。 我需要一个解决方法。

公共类MainActivity扩展活动
 {
     @覆盖
    保护无效的onCreate(Bundle savedInstanceState)
     {
         super.onCreate(savedInstanceState);
        的setContentView(R.layout.activity_main);
     } 

 @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; } public void onClickBtn(View view) { Intent flowIntent = new Intent(this, SecondActivity.class); startActivity(flowIntent); } 

}

公共类SecondActivity扩展活动
{
@覆盖
保护无效的onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
的setContentView(R.layout.activity_second);
}

 @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; } public void onClickBtn(View view) { Intent flowIntent = new Intent(this, MainActivity.class); flowIntent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT); startActivity(flowIntent); } 

}

performance:

 <?xml version =“1.0”encoding =“utf-8”?>
 <manifest xmlns:android =“ http://schemas.android.com/apk/res/android&quot ;
    包= “com.example.tester”
    机器人:的versionCode = “1”
     android:versionName =“1.0”>
  <uses-permission android:name =“android.permission.INTERNET”/>
     <uses-permission android:name =“android.permission.ACCESS_NETWORK_STATE”/>
     <用途-SDK
        机器人:的minSdkVersion = “8”
         android:targetSdkVersion =“18”/>
     <应用
        机器人:allowBackup = “真”
        机器人:图标= “@绘制/ ic_launcher”
        机器人:标签= “@string/ APP_NAME”
         android:theme =“@ style / AppTheme”>
         <活动
            机器人:名字= “com.example.tester.MainActivity”
             android:label =“@ string / app_name”>
             <意图滤波器>
                 <action android:name =“android.intent.action.MAIN”/>
                 <category android:name =“android.intent.category.LAUNCHER”/>
             </意图滤波器>
         </活动>
          <活动
             android:name =“com.example.tester.SecondActivity”/>
     </应用>
 </清单>

Solutions Collecting From Web of "令人费解的行为与REORDER_TO_FRONT"

http://code.google.com/p/android/issues/detail?id=63570#c2

它已经被谷歌确认为4.4.2的一个bug

首先,让我们先说你是对的 !

但是,如果我的逻辑是正确的,当你在主要ActivityLauncher Activity )中REORDER时会发生什么情况,Intent被设置为使得后退将返回到Launcher

作为一个实验,尝试添加Activity C,并尝试从C的前面B到前面。即:
A-> B-> C … A-> C-> B

如果顺序对您非常重要,您可能需要重写Activity.onNewIntent()方法。

 @Override protected void onNewIntent(Intent intent) { } 

我发现这个bug的一个简单的解决方法。

覆盖onNewIntent并完成任何可能重新sorting前面的活动的function,因为以下将做一个诡计,只是没有太充分的testing,如果你发现这个解决方法的任何问题,请与我联系ricotta.zhang@myriadgroup.com

 @Override protected void onNewIntent(Intent intent) { super.onNewIntent(intent); if ((intent.getFlags() | Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) > 0) { mIsRestoredToTop = true; } } @Override public void finish() { super.finish(); if (android.os.Build.VERSION.SDK_INT >= 19 && !isTaskRoot() && mIsRestoredToTop) { // 4.4.2 platform issues for FLAG_ACTIVITY_REORDER_TO_FRONT, // reordered activity back press will go to home unexpectly, // Workaround: move reordered activity current task to front when it's finished. ActivityManager tasksManager = (ActivityManager) getSystemService(ACTIVITY_SERVICE); tasksManager.moveTaskToFront(getTaskId(), ActivityManager.MOVE_TASK_NO_USER_ACTION); } } 

我根本找不到这个问题。 这是我创build的项目 。

我刚刚overrided onFinish()方法来检查哪个活动被closures。

我遇到了这个bug,并决定我可能需要解决它。 至less在我的情况下,通过为4.4.2版本提供一个自定义的back stack实现似乎是可能的。 这绝非漂亮,可能无法在所有情况下工作,但它确实节省了我和我的基于DrawerLayout的导航。

首先,我有一个NavigationDrawerActivity作为所有其他活动扩展的类。 在那里,我有一个被称为类的静态Stack以及一个可以从导航抽屉访问的类的数组。 addClassToStack方法是公共的,除了抽屉之外的其他导航方式也可以使用堆栈。 请注意,如何将要添加到堆栈的类首先移除(如果存在),以便获得通常由再命令至前置标志提供的相同function。 我已经用版本检查包围了hacky代码,以便在必要时才使用hack。

 public class NavigationDrawerActivity extends Activity { ... private static Stack<Class<?>> classes = new Stack<Class<?>>(); private Class<?>[] activity_classes; ... public static void addClassToStack(Class<?> to_add) { if (android.os.Build.VERSION.RELEASE.equals("4.4.2")) { classes.remove(to_add); classes.push(to_add); } } ... 

接下来是导航抽屉的监听器类。 我的抽屉上的button是在一个ListView所以每当用户想要去某个地方, onItemClick这里将被调用。 这里唯一的“黑客”就是调用addClassToStack来添加新的活动作为后端堆栈的顶端。

  private class DrawerItemClickListener implements ListView.OnItemClickListener { private Intent i; @Override public void onItemClick(AdapterView<?> parent, View v, int pos, long id) { i = new Intent(NavDrawerActivity.this, activity_classes[pos]); addClassToStack(activity_classes[pos]); i.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT); nav_drawer.closeDrawers(); startActivity(i); } } 

解决方法的最后一部分是重写onKeyDown方法,如果在Android 4.4.2上按下了后退button(并且我们超出了导航中的第一个活动),则要从我们的自定义后台堆栈中提取要打开的活动并直接调用。 请注意,堆栈中最顶端的项目总是当前的活动,因此我们需要摆脱这一点,并使用第二个作为目标。 另外请注意,如何返回到第一个活动清除正式的任务历史logging。 这是必需的,因为否则,在再次按下并返回到主屏幕之后,下次访问应用程序时,它直接进入正式返回堆栈的顶部。

  @Override public boolean onKeyDown(int keyCode, KeyEvent event) { boolean handled = false; if (keyCode == KeyEvent.KEYCODE_BACK && android.os.Build.VERSION.RELEASE.equals("4.4.2") && classes.size() > 1) { classes.pop(); Intent prev = new Intent(this, classes.peek()); if (classes.size() == 1) { prev.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); } else { prev.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT); } startActivity(prev); handled = true; } if (!handled) { return super.onKeyDown(keyCode, event); } else { return true; } } } 

剩下的唯一东西(在这里没有显示)是在适当的位置分别添加初始活动(在应用程序启动时打开的活动)到后退栈中。 在我的应用程序中,我有一个单独的启动屏幕,不能通过导航抽屉访问,所以我可以从该活动的onCreate调用NavigationDrawerActivity.addClassToStack(StartScreenActivity.class) 。 对于其他结构,您可能会做一些不同的事情,以确保初始活动仅作为第一项添加到堆栈中。

现在,这是一个黑客,我还没有完全testing,但似乎在Nexus 4(4.4.2)和Nexus S(坚持4.1)上工作。 所以,如果你尝试做这样的事情,那不行,不要生气,反而让我知道。 🙂