【问题标题】:Puzzling behavior with REORDER_TO_FRONTREORDER_TO_FRONT 令人费解的行为
【发布时间】:2018-04-24 06:29:33
【问题描述】:

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

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

这是预期的行为,我只是没有正确理解它吗?

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

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

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

}

公共类 SecondActivity 扩展了 Activity { @覆盖 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);

}

}

清单:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="@987654321@;
    package="com.example.tester"
    android:versionCode="1"
    android:versionName="1.0" >
 <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="18" />
    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.example.tester.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
         <activity
            android:name="com.example.tester.SecondActivity" />
    </application>
</manifest>

【问题讨论】:

  • 能否请您发布您的清单?
  • 请发布您的主题

标签: android


【解决方案1】:

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

已被 google 确认为 4.4.2 上的错误

【讨论】:

  • 显然至少一直到 5.1.1 - 关于 6.0 的任何消息?
  • 我什至可以在 N Preview 2 上看到这个错误
【解决方案2】:

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

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

作为一个实验,尝试将ActivityC 和REORDERB 从C 加到前面。 那就是:
A->B->C ... A->C->B

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

@Override
protected void onNewIntent(Intent intent) {
}

【讨论】:

  • setIntent(intent) 没有解决问题,行为还是一样。
  • "作为一个实验,尝试添加Activity C,并尝试将B从C重新排序到前面。即:A->B->C ... A->C->B"这按预期工作。此外,如果您将 Activity C REORDER A 置于前面(因此为 B-C-A),此时按下 Activity A 的后退按钮将按预期返回 C 而不是启动器。我只能推测我最初给出的两个Activity示例中的行为是框架中的一个BUG!
【解决方案3】:

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

重写 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);
    }
}

【讨论】:

  • 好像需要android.permission.REORDER_TASKS
【解决方案4】:

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

我刚刚重写了 onFinish() 方法来检查哪个 Activity 关闭了。

【讨论】:

  • 什么版本?到目前为止,我只在 4.4.2 上测试过。我想这可能是特定于版本的事件。
  • 检查您的设备或模拟器上的示例。我检查了 android-19,即 Android 4.4 Kitkat。
  • 试过你的项目,显然是 4.4.2 框架中的一个错误。我的 4.4.2 设备和 4.4.2 模拟器都有错误的行为。在 4.3 和 4.1.2 模拟器上,行为是正确的。您是否将 SDK 更新到 4.4.2?我相信你也会看到的。请更新您的答案以包括这显然是特定于版本的错误,我将奖励赏金。我要报告错误。
  • 我检查了 Android 4.2.2 设备。已更新最新的 Android 4.4.2 版本,但需要检查 4.4.2 的模拟器
【解决方案5】:

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

首先,我有一个NavigationDrawerActivity 作为所有其他活动扩展的类。在那里,我有一个静态 Stack 用于调用的类以及可以从导航抽屉访问的类数组。 addClassToStack 方法是公共的,因此除了抽屉之外的其他导航方式也可以使用堆栈。请注意如何首先删除要添加到堆栈的类(如果存在),以便我们获得与 reorder-to-front 标志通常提供的相同功能。我已经用版本检查包围了 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)。对于其他结构,您可能会做一些不同的事情来确保初始活动仅作为第一项添加到堆栈中。

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

【讨论】:

    【解决方案6】:

    我看到这个问题发生在 S7 7.0 操作系统上,当活动设置为标志 Intent.FLAG_ACTIVITY_REORDER_TO_FRONT 并且此活动自行完成时,用户将被带到设备的主屏幕。

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

    通过这种方式,新的 Activity 实例被推送到堆栈,并且由于 noHistory 为真,因此已经是堆栈一部分的旧实例被销毁。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-10-30
      • 2018-07-02
      • 2020-06-19
      • 2023-03-12
      • 1970-01-01
      • 1970-01-01
      • 2011-03-27
      • 2010-11-15
      相关资源
      最近更新 更多