令人费解的行为与REORDER_TO_FRONT

时间:2013-12-20 02:52:11

标签: android

活动A启动没有标志的活动B.堆栈现在是A-B,顶部是B. B使用FLAG_ACTIVITY_REORDER_TO_FRONT(唯一标志)启动活动A.我希望这个堆栈现在是B-A。但是,当此时按下后退按钮时,它将返回主屏幕。在这里,我希望将活动B带到前面。再次单击启动器图标后,应用程序将打开,其中B为运行活动,堆栈中没有任何内容。

Launchmode是清单中的标准(默认)。

这是预期的行为吗?我只是不能正确理解它?

编辑:我创建了一个没有混淆因素的测试项目,但仍然看到相同的行为。我只是不理解它,它似乎不是根据文档。

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

public class MainActivity extends Activity
{
    @Override
    protected void 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);
}

}

public class SecondActivity extends Activity { @Override protected void 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);

}

}

清单: @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); }

@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);

}

6 个答案:

答案 0 :(得分:21)

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

谷歌已经确认这是4.4.2的错误

答案 1 :(得分:8)

首先,让我们先说you're right

但是如果我的逻辑是正确的,那么当你REORDER到你的主ActivityLauncher Activity)时会发生什么,意图被设置为背压将返回Launcher

作为实验,尝试添加Activity C并尝试将REORDER B从C开始到前面。 那就是:
A-> B-> C ... A-> C-> B

如果订单对您非常重要,您可能需要覆盖Activity.onNewIntent()方法。

@Override
protected void onNewIntent(Intent intent) {
}

答案 2 :(得分:7)

我找到了这个错误的简单解决方法。

覆盖onNewIntent并完成任何可能重新排序到前台活动的功能,如下所示,只是不完全测试,如果您发现此解决方法有任何问题,请通过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);
    }
}

答案 3 :(得分:2)

我根本找不到这个问题。 Here is the project I have created

我刚刚用overFinish()方法来检查哪个Activity已关闭。

答案 4 :(得分:1)

我也遇到了这个错误,并决定我可能需要解决它。至少在我的情况下,似乎可以通过为版本4.4.2提供自定义后台堆栈实现。这绝不是漂亮的,并且可能无法在所有情况下都有效,但它确实保存了我和基于DrawerLayout的导航。

首先,我有一个NavigationDrawerActivity作为所有其他活动扩展的类。在那里,我有一个静态Stack用于被调用的类以及可以从导航抽屉访问的类数组。 addClassToStack方法是公共的,因此除了抽屉之外的其他导航方式也可以使用堆栈。注意如何首先删除要添加到堆栈中的类(如果存在),以便我们获得与重订单到前端标志通常提供的相同的功能。我用版本检查包围了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);
        }
    }
    ...

接下来是导航抽屉的监听器类。抽屉上的按钮位于ListView,因此每次用户想要去某处时,都会调用此处的onItemClick。这里唯一的“hacky”是调用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上按下后退按钮(我们超出导航中的第一个活动),则要打开的活动从我们的自定义后台堆栈中获取并直接调用。请注意,堆栈中最顶层的项目始终是当前活动,因此我们需要摆脱它并使用第二个项目作为目标。还要注意我在返回第一个活动时如何清除正式任务历史记录。这是必需的,因为否则,在再次按下并返回主屏幕后,下次访问该应用程序时,它会直接进入官方后台堆栈的顶部。

    @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)。对于其他结构,您可能会做一些不同的事情,以确保初始活动仅作为第一个项目添加到堆栈中。

现在,这是一个黑客,我还没有彻底测试过,但它似乎也适用于Nexus 4(4.4.2)和Nexus S(卡在4.1上)。因此,如果你尝试做这样的事情并且它不起作用,不要生气但是让我知道。 :)

答案 5 :(得分:0)

我发现这个问题发生在S7 7.0操作系统上,当使用Flag Intent.FLAG_ACTIVITY_REORDER_TO_FRONT设置活动并且此活动结束时,用户将进入设备的主屏幕。

我为此修好了 - 删除了标志Intent.FLAG_ACTIVITY_REORDER_TO_FRONT并添加了noHistory = true

这样新的活动实例就会被推送到堆栈,因为noHistory为true,旧的实例已经是堆栈的一部分被破坏了。