Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/198.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android JetPack多栈导航_Android_Android Architecture Components_Android Jetpack_Android Architecture Navigation - Fatal编程技术网

Android JetPack多栈导航

Android JetPack多栈导航,android,android-architecture-components,android-jetpack,android-architecture-navigation,Android,Android Architecture Components,Android Jetpack,Android Architecture Navigation,我正在使用Jetpack Navigation版本1.0.0-alpha04和底部导航。它可以工作,但导航不正确。例如,如果我有选项卡A和选项卡B,我从选项卡A转到第C页,从那里我转到选项卡B并再次回到选项卡A,我将在选项卡A中看到根片段,而不是我所期望的第C页。 我正在寻找一种解决方案,为每个选项卡提供不同的堆栈,因此当我返回时,每个选项卡的状态都是保留的,而且我不喜欢将所有这些片段保留在内存中,因为它对性能有不良影响,在jetpack导航之前,我使用了这个库,这正是,现在我正在寻找与喷气背

我正在使用Jetpack Navigation
版本1.0.0-alpha04
和底部导航。它可以工作,但导航不正确。例如,如果我有选项卡A和选项卡B,我从选项卡A转到第C页,从那里我转到选项卡B并再次回到选项卡A,我将在选项卡A中看到根片段,而不是我所期望的第C页。 我正在寻找一种解决方案,为每个选项卡提供不同的堆栈,因此当我返回时,每个选项卡的状态都是保留的,而且我不喜欢将所有这些片段保留在内存中,因为它对性能有不良影响,在jetpack导航之前,我使用了这个库,这正是,现在我正在寻找与喷气背包导航相同的东西。

编辑2:尽管仍然没有一流的支持(截至撰写本文之时),谷歌现在已经用一个他们认为目前应该如何解决这一问题的示例更新了他们的示例:


主要原因是您只使用一个
NavHostFragment
来保存应用程序的整个后台堆栈

解决方案是每个选项卡都应该保留自己的后台堆栈

  • 在主布局中,用
    FrameLayout
    包装每个选项卡片段
  • 每个选项卡片段都是一个
    NavHostFragment
    ,并包含自己的导航图,以便使每个选项卡片段都有自己的后堆栈
  • BottomNavigationView.OnNavigationItemSelectedListener
    添加到
    BottomNavigtionView
    以处理每个框架布局的可见性
这也会考虑到您的“…我不想将所有这些片段都保留在内存中…”,因为默认情况下使用
NavHostFragment
的导航使用
fragmentTransaction.replace()
,即您始终只会拥有与
NavHostFragment
相同的片段。其余的就在导航图的后堆栈中

编辑:谷歌正在进行本机实现


更多详细信息

假设您有一个
底部导航视图
,有两个菜单选项,

<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@+id/dogMenu"
        .../>

    <item android:id="@+id/catMenu"
        .../>
</menu>
以及对应的
cat\u导航图

activity\u main.xml
中,添加2个
NavHostFragment
s

<FrameLayout
    android:id="@+id/frame_dog"
    ...>

    <fragment
        android:id="@+id/dog_navigation_host_fragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:name="androidx.navigation.fragment.NavHostFragment"
        app:navGraph="@navigation/dog_navigation_graph"
        app:defaultNavHost="true"/>
</FrameLayout>
showHostView()
所做的只是切换正在包装
NavHostFragment
s的
FrameLayout
s的可见性。因此,请确保以某种方式保存它们,例如在
onCreateView

val hostViews = arrayListOf<FrameLayout>()  // Member variable of MainActivity
hostViews.apply {
    add(findViewById(R.id.frame_dog))
    add(findViewById(R.id.frame_cat))
}
val hostViews=arrayListOf()//MainActivity的成员变量
hostViews.apply{
添加(findViewById(R.id.frame_dog))
添加(findViewById(R.id.frame_cat))
}

现在很容易切换哪些主机视图应该是可见的和不可见的。

首先,我想对@Algar的答案进行编辑。要隐藏的帧应该具有
android:visibility=“gone”
,而不是
不可见的
。在主布局中,这样做的原因如下:

    <LinearLayout 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:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        tools:context=".ui.activity.MainActivity">
    
        <include
            android:id="@+id/toolbar"
            layout="@layout/toolbar_base" />
    
        <FrameLayout
            android:id="@+id/frame_home"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="2"
            >
            <fragment
                android:id="@+id/home_navigation_host_fragment"
                android:name="androidx.navigation.fragment.NavHostFragment"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                app:defaultNavHost="true"
                app:navGraph="@navigation/home_nav" />
        </FrameLayout>
        <FrameLayout
            android:id="@+id/frame_find"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="2"
            android:visibility="gone">
    
            <fragment
                android:id="@+id/find_navigation_host_fragment"
                android:name="androidx.navigation.fragment.NavHostFragment"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                app:defaultNavHost="true"
                app:navGraph="@navigation/find_nav" />
        </FrameLayout>
        ...
    
   </LinearLayout>

Android团队已在最新版本2.4.0-alpha01中解决了该问题。现在,无需任何解决方法,即可实现多个Backbackback和底部导航支持


能否发布活动的onCreate和OnNavigationItemSelectedListener代码?这将有助于查看您已经尝试过的内容。在此上下文中,页面是什么?另一项活动?还是选项卡a中的视图?可能是寻呼机?@NickCardoso page是一个片段,我在每个选项卡中都有根片段,当发生某些事件时,我们会转到该选项卡中的下一个片段。@Reza找到解决方案了吗?@Armin还没有!不过我有兴趣找到更好的答案。所以,如果你发现了什么,也请告诉我。这可能有效,但如果我这样做,我的内存中同时有五个片段,而其中只有一个被使用。你建议如何解决这个问题?是的,这就是你获得良好用户体验的方式:)。无论哪种方式,如果用户在应用程序周围导航,您都希望保留每个后台堆栈。。这不是一开始的问题吗?好吧,我试图实现的是有单独的后堆栈,而内存中只有一个片段,其他片段只存在于堆栈中。我知道这很难,但这应该是可能的,你可以看看这个例子哦,是的,现在我明白你的意思了。这是一个值得思考的细微差别!也许一个
ViewPager
是一个不错的选择,但我还没有在导航方面尝试过。“我得看一看。”雷扎在我没有第一次感到那么累的时候,我想到了你的观点,我突然意识到从来没有出现过问题。我用解释更新了答案(请参见
fragmentTransaction.replace()
),并添加了完整的代码示例。
val hostViews = arrayListOf<FrameLayout>()  // Member variable of MainActivity
hostViews.apply {
    add(findViewById(R.id.frame_dog))
    add(findViewById(R.id.frame_cat))
}
    <LinearLayout 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:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        tools:context=".ui.activity.MainActivity">
    
        <include
            android:id="@+id/toolbar"
            layout="@layout/toolbar_base" />
    
        <FrameLayout
            android:id="@+id/frame_home"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="2"
            >
            <fragment
                android:id="@+id/home_navigation_host_fragment"
                android:name="androidx.navigation.fragment.NavHostFragment"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                app:defaultNavHost="true"
                app:navGraph="@navigation/home_nav" />
        </FrameLayout>
        <FrameLayout
            android:id="@+id/frame_find"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="2"
            android:visibility="gone">
    
            <fragment
                android:id="@+id/find_navigation_host_fragment"
                android:name="androidx.navigation.fragment.NavHostFragment"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                app:defaultNavHost="true"
                app:navGraph="@navigation/find_nav" />
        </FrameLayout>
        ...
    
   </LinearLayout>
@Override
protected void onRestoreInstanceState(@NonNull Bundle savedInstanceState) {
    super.onRestoreInstanceState(savedInstanceState);
    //if this activity is restored from previous state,
    //we will have the ItemId of botnav the has been selected
    //so that we can set up nav controller accordingly
    switch (bottomNav.getSelectedItemId()) {
        case R.id.home_fragment:
            curNavHostFragment = homeNavHostFragment;
            ...
            break;
        case R.id.find_products_fragment:
            curNavHostFragment = findNavHostFragment;
            ...
            break;
    
    }
    curNavController = curNavHostFragment.getNavController();