【问题标题】:Different backstack behavior between Nexus 6 device and emulatorNexus 6 设备和模拟器之间的不同回栈行为
【发布时间】:2015-06-19 01:40:39
【问题描述】:

我正在开发一个应用程序,该应用程序支持 FragmentSearchView 小部件和 RecyclerView 以显示搜索结果,该搜索结果将用户发送到 FragmentActivity 以显示选择的详细信息。所有这些都可以正常工作,但我看到 Nexus 6 模拟器和实际设备之间关于 backstack 的行为不一致。在模拟器中,一切正常,如果在详细信息 FragmentActivity 上按下返回按钮,用户将返回搜索结果片段。在实际的 Nexus 6 设备上,用户会一直返回到包含我的应用程序菜单的 AppCompatActivity(此活动使用支持 FragmentManager,它将其管理的片段添加到后台堆栈):

private void replaceFragment(Fragment supportFragment) {
    String fragmentName = supportFragment.getClass().getSimpleName();
    supportFragmentManager.beginTransaction()
            .addToBackStack(fragmentName)
            .replace(R.id.frame_menu_container, supportFragment, fragmentName)
            .commit();
}

将用户从 Fragment 发送到 FragmentActivity 的代码只是一个带有附加功能的意图:

Intent intent = new Intent(getActivity(), PlayerDetailsActivity.class);
intent.putExtra(TransientPlayer.BUNDLE_KEY, transientPlayer);
startActivity(intent);

我还没有对 backstack 做任何特别的事情——这是默认行为。

这可能是什么问题?我已经阅读了一些关于 backstack 的内容,但是当您从 FragmentActivy 返回到不使用 FragmentManager 的 Fragment 时,我还没有看到任何手动添加内容到 backstack 的内容。

编辑 1:这是定义 frame_menu_container 的布局 XML:

<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:gravity="center"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:background="?attr/colorPrimary"
        android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
        app:popupTheme="@style/ThemeOverlay.AppCompat.Light"/>

    <FrameLayout
        android:id="@+id/frame_menu_container"
        android:layout_below="@id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:layout="@layout/fragment_home">
    </FrameLayout>

</RelativeLayout>

编辑 2:好的,这是我的高级活动和片段的文字描述:

NavigationMenuActivity,扩展 AppCompatActivity。这是根据需要换入和换出所有片段的地方,使用SupportFragmentManager 并且我有replaceFragment() 方法。

我有以下片段,所有这些片段要么显示静态信息,要么进行 REST 调用以检索和显示数据,要么允许用户发送反馈。都是扩展android.support.v4.app.Fragment,没有一个有其他的碎片或活动用户可以去。

  • 主页片段
  • 日历片段
  • StandingsFragment
  • PlayerSearchFragment(见下文)
  • 关于片段
  • 反馈片段

这些片段的唯一例外是PlayerSearchFragment,它也扩展了android.support.v4.app.Fragment。此片段包含一个RecyclerView,当用户想要搜索玩家时,它会显示 REST 调用的结果。当返回结果并且用户从列表中选择一个项目时,它们将被发送到扩展 FragmentActivityPlayerDetailsActivity

PlayerDetailsActivity 使用FragmentTabHost 视图,其中包含可以查看的有关玩家的不同类型的信息。这是这条路径的“终点”——用户无法访问其他片段或活动。这就是问题所在。当我在此活动中点击返回按钮时,我的意图是让用户返回PlayerSearchFragment 片段(搜索结果),在这种情况下,如果我在 Nexus 6 模拟器中,他们会这样做,但如果我使用的是实际的 Nexus 6 设备,它们会一直返回 NavigationMenuActivity 活动。

我在PlayerDetailsActivity 中有以下方法,当按下后退按钮时会调用它,但它总是显示零条目:

@Override
public void onBackPressed() {

    FragmentManager fragmentManager = getSupportFragmentManager();
    int count = fragmentManager.getBackStackEntryCount();
    Log.i(TAG, "Backstack : There are " + count + " entries");
    for (int i = 0; i > count; i++) {
        FragmentManager.BackStackEntry backStackEntry = fragmentManager.getBackStackEntryAt(i);
        Log.i(TAG, String.format("Backstack : id=%d, name=%s, shortTitle=%s, breadcrumbTitle=%s",
                backStackEntry.getId(),
                backStackEntry.getName(),
                backStackEntry.getBreadCrumbShortTitle(),
                backStackEntry.getBreadCrumbTitle()));
    }

    super.onBackPressed();
}

我希望所有设备的体验都相同,无论是硬件还是模拟器。

【问题讨论】:

  • 发布包含 frame_menu_container 的布局。我认为它可能不适合片段的 UI 元素。
  • 我已经在上面添加了
  • 搜索是一个fragmentactivity? & 结果是一个片段?如果我错了,你为什么要使用意图顺便说一句对不起
  • 我在 EDIT 2 中添加了更多信息
  • “几个活动”?整个应用程序中只有两个。我不确定你的意思。

标签: android android-fragments fragment-backstack


【解决方案1】:

我想你希望 addToBackStack(fragmentName)replace(R.id.frame_menu_container, supportFragment, fragmentName) 之后调用。

告诉我会发生什么。

【讨论】:

  • 不幸的是,这并没有解决我的问题 - 它仍然表现出相同的行为。
  • 您实际上是在替换之前调用 addToBackStack ,因此您应该将其删除并将其置于替换下方 @TheIcemanCometh 或者您就是这样做的?
  • @Elltz 这就是我最初所做的,是的。进行建议的更改/切换似乎没有帮助。现在查看其他建议。
【解决方案2】:

根据您的场景,您不需要将事务添加到 BackStack,因为它仅在您在同一活动的片段之间导航时使用。

现在你的另一点是,当你按下你没有得到你的片段时,你点击了两次。单击一次删除您的第二个活动,另一次单击删除添加到您的后台堆栈中的片段。至于您的信息 Fragment 没有 backpress 回调,它们依赖于活动 onbackPressed() 方法

我尝试运行此代码,它在我的 Nexus 5 设备上正常运行。 虽然我附上了我正在使用的代码

public class MainActivity extends FragmentActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    replaceFragment(new FragmentA());


}
private void replaceFragment(Fragment supportFragment) {

    getSupportFragmentManager().beginTransaction()
            .replace(R.id.frame_menu_container, supportFragment
            .commit();
}

}

片段A在这里:

 public class FragmentA extends Fragment {
    @Nullable
    @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.fragment_a, null);

    view.findViewById(R.id.btn).setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Intent intent = new Intent(getActivity(), AnotherActivity.class);
            startActivity(intent);
        }
    });
    return view;
}

}

另一个活动是这样的:

public class AnotherActivity extends Activity {

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.another_act);

}

}

我不认为你应该面对任何问题。

如果您仍然遇到问题,请告诉我您的设备名称并在此处附上代码,以便我进行测试并通知您。

【讨论】:

  • 我删除了对addToBackStack()的调用,但没有任何效果
【解决方案3】:

试试这个,希望能让你摆脱这个错误的洞。

这个答案给你一个解决方法,但不是真正发生的事情

@Override
public void onBackPressed() {

FragmentManager fragmentManager = getSupportFragmentManager();
int count = fragmentManager.getBackStackEntryCount();
Log.i(TAG, "Backstack : There are " + count + " entries");
if(count > 0){
    fragmentManager.popBackStack(); //or  popBackStackImmediate();
    for (int i = 0; i > count; i++) {
         FragmentManager.BackStackEntry backStackEntry = fragmentManager.getBackStackEntryAt(i);
         Log.i(TAG, String.format("Backstack : id=%d, name=%s, shortTitle=%s, breadcrumbTitle=%s",
            backStackEntry.getId(),
            backStackEntry.getName(),
            backStackEntry.getBreadCrumbShortTitle(),
            backStackEntry.getBreadCrumbTitle()));
   }
}else{
super.onBackPressed();
}

}

【讨论】:

  • 对于 backstack 条目计数,这仍然返回零。
  • 真的吗?尝试将 addtobackstack 调用和 replace 调用分开,然后分别调用comit 并查看。@TheIcemanCometh
【解决方案4】:

虽然我仍然不知道为什么我无法让它按照我希望的方式工作,但我确实有一个解决方法,它确实适用于我需要做的事情。基本上,我覆盖了PlayerDetailsActivity 中的向上和返回导航回调,并使用意图(带有数据)将用户显式发送回NavigationMenuActivity。我在 Intent 中发送的数据基本上只是一个布尔值,它告诉我我是否来自 PlayerDetailsActivity,如果是,则显示该片段而不是 Home 片段,如下所示:

@Override
public void onBackPressed() {
    sendBackToMenu();
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
        case android.R.id.home:
            sendBackToMenu();
            finish();
            return true;
    }
    return false;
}

private void sendBackToMenu() {
    Intent backToMenuIntent = new Intent(this, NavigationMenuActivity.class);
    backToMenuIntent.putExtra("FROM_PLAYER_DETAILS", true);
    startActivity(backToMenuIntent);
}

上述更改是在我将类更改为从AppCompatActivity 扩展并在PlayerDetailsActivity.onCreate() 中添加以下内容以激活向上导航的ActionBar 之后:

ActionBar actionBar = getSupportActionBar();
assert actionBar != null;
actionBar.setTitle(R.string.player_details);
actionBar.setDisplayHomeAsUpEnabled(true);

另外,在NavigationMenuActivity.onCreate() 我这样做:

if (getIntent().getBooleanExtra("FROM_PLAYER_DETAILS", false))
    replaceFragment(new PlayerSearchFragment());
else           
    replaceFragment(new HomeFragment());

我不知道这是否是最“合适”的方法,但它运行良好,并且可以在少数硬件设备和 Nexus 4/5/6 模拟器上满足我的需求。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-26
    • 1970-01-01
    • 1970-01-01
    • 2011-05-26
    • 2020-02-27
    • 1970-01-01
    相关资源
    最近更新 更多