【问题标题】:My fragments keep recreating whenever I reclick or navigate to the next fragment每当我重新单击或导航到下一个片段时,我的片段都会不断重新创建
【发布时间】:2019-12-08 06:05:32
【问题描述】:

我已经在我的 android 应用程序上实现了新的架构组件,但不幸的是,处理这些片段的状态对我来说已成为一场噩梦。每当我按下片段的图标时,每次导航时都会重新创建片段。我该如何处理或者保存这些片段状态?

这是我处理五个片段的主要活动:

public class MainActivityCenterofInformation extends AppCompatActivity {

    BottomNavigationView bottomNavigationView;

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

        setUpNavigation ();
    }

    public  void setUpNavigation(){
        bottomNavigationView = findViewById (R.id.bottom_nav_cict);
        NavHostFragment navHostFragment = (NavHostFragment)getSupportFragmentManager ()
                .findFragmentById (R.id.nav_host_fragment_cict);
        NavigationUI.setupWithNavController (bottomNavigationView, navHostFragment.getNavController ());
    }

    //adding animations to the fragment
}

我看不懂 Kotlin,所以请指导我使用 Java,谢谢。

【问题讨论】:

    标签: java android android-fragments


    【解决方案1】:

    TL;DR: 跳到 只需向我展示已完成的步骤!!! 部分

    这是片段的正常行为。假设每次删除或替换它们时都会重新创建它们,并且假设您使用 onSaveInstanceState 恢复它们的状态。

    这是一篇很好的文章,描述了如何做到这一点:Saving Fragment States

    除此之外,您还可以使用View Model,这是以下推荐的 android 架构的一部分。它们是保留和恢复 UI 数据的好方法。

    你可以按照这个步骤一步一步来学习如何实现这个架构code lab

    编辑:解决方案

    花了一段时间,但它就在这里。解决方案目前不使用ViewModels

    仔细阅读,因为每一步都很重要。该解决方案包括以下两部分

    • 在后退键按下时实现正确导航
    • 在导航期间保持片段活动

    背景:

    Android Navigation 组件提供了一个NavController 类,您可以使用它在不同的目的地之间导航。在内部 NavController 使用 Navigator 实际进行导航。 Navigator 是一个抽象类,任何人都可以扩展/继承此类以创建自己的自定义导航器,以根据目的地类型提供自定义导航。当使用片段作为目的地时,NavHostFragment 使用FragmentNavigator,其默认实现会在我们使用FragmentTransaction.replace() 导航时替换片段,这会完全破坏先前的片段并添加新片段。所以我们必须创建自己的导航器,而不是使用FragmentTransaction.replace(),我们将使用FragmentTransaction.hide()FragmentTransaction.show() 的组合来避免片段被破坏。

    导航 UI 的默认行为:

    默认情况下,每当您导航到除主/起始片段以外的任何其他片段时,它们都不会被添加到后台堆栈中,因此假设您按以下顺序选择片段

    A -> B -> C -> D -> E
    

    你的后台只有

    [A, E]
    

    你可以看到片段 B、C、D 没有被添加到 backstack,所以按下回压总是会让你回到片段 A,它是主片段

    我们现在想要的行为:

    我们想要一个简单而有效的行为。我们不希望将所有片段都添加到 backstack,但如果片段已经在 backstack 中,我们希望将所有片段弹出到所选片段。

    假设我按以下顺序选择片段

    A -> B -> C -> D -> E
    

    backstack也应该是

    [A, B, C, D, E]
    

    按下后,只有最后一个片段应该被弹出,并且 backstack 应该是这样的

    [A, B, C, D]
    

    但是如果我们导航到片段 B,因为 B 已经在堆栈中,那么 B 上面的所有片段都应该被弹出,我们的 backstack 应该看起来像这样

     [A, B]
    

    我希望这种行为是有意义的。使用全局操作很容易实现此行为,如下所示,并且比默认行为更好。

    好帅!怎么办 ? :

    现在我们有两个选择

    1. 扩展FragmentNavigator
    2. 复制/粘贴FragmentNavigator

    我个人只想扩展 FragmentNavigator 并覆盖 navigate() 方法,但由于它的所有成员变量都是私有的,我无法实现正确的导航。

    所以我决定复制粘贴整个 FragmentNavigator 类,并将整个代码中的名称从 "FragmentNavigator" 更改为我想调用的任何名称。

    只要告诉我步骤就行了!!! :

    1. 创建自定义导航器
    2. 使用自定义标签
    3. 添加全局操作
    4. 使用全局操作
    5. 将自定义导航器添加到 NavController

    第 1 步:创建自定义导航器

    这是我的自定义导航器,名为StickyCustomNavigator。除了navigate() 方法外,所有代码都与FragmentNavigator 相同。如您所见,它使用hide()show()add() 方法而不是replace()。逻辑很简单。隐藏前一个片段并显示目标片段。如果这是我们第一次访问特定的目标片段,请添加片段而不是显示它。

    @Navigator.Name("sticky_fragment")
    public class StickyFragmentNavigator extends Navigator<StickyFragmentNavigator.Destination> {
    
    
        private static final String TAG = "StickyFragmentNavigator";
        private static final String KEY_BACK_STACK_IDS = "androidx-nav-fragment:navigator:backStackIds";
    
        private final Context mContext;
        @SuppressWarnings("WeakerAccess") /* synthetic access */
        final FragmentManager mFragmentManager;
        private final int mContainerId;
        @SuppressWarnings("WeakerAccess") /* synthetic access */
                ArrayDeque<Integer> mBackStack = new ArrayDeque<>();
        @SuppressWarnings("WeakerAccess") /* synthetic access */
                boolean mIsPendingBackStackOperation = false;
    
        private final FragmentManager.OnBackStackChangedListener mOnBackStackChangedListener =
                new FragmentManager.OnBackStackChangedListener() {
    
                    @SuppressLint("RestrictedApi")
                    @Override
                    public void onBackStackChanged() {
                        // If we have pending operations made by us then consume this change, otherwise
                        // detect a pop in the back stack to dispatch callback.
                        if (mIsPendingBackStackOperation) {
                            mIsPendingBackStackOperation = !isBackStackEqual();
                            return;
                        }
    
                        // The initial Fragment won't be on the back stack, so the
                        // real count of destinations is the back stack entry count + 1
                        int newCount = mFragmentManager.getBackStackEntryCount() + 1;
                        if (newCount < mBackStack.size()) {
                            // Handle cases where the user hit the system back button
                            while (mBackStack.size() > newCount) {
                                mBackStack.removeLast();
                            }
                            dispatchOnNavigatorBackPress();
                        }
                    }
                };
    
        public StickyFragmentNavigator(@NonNull Context context, @NonNull FragmentManager manager,
                               int containerId) {
            mContext = context;
            mFragmentManager = manager;
            mContainerId = containerId;
        }
    
        @Override
        protected void onBackPressAdded() {
            mFragmentManager.addOnBackStackChangedListener(mOnBackStackChangedListener);
        }
    
        @Override
        protected void onBackPressRemoved() {
            mFragmentManager.removeOnBackStackChangedListener(mOnBackStackChangedListener);
        }
    
        @Override
        public boolean popBackStack() {
            if (mBackStack.isEmpty()) {
                return false;
            }
            if (mFragmentManager.isStateSaved()) {
                Log.i(TAG, "Ignoring popBackStack() call: FragmentManager has already"
                        + " saved its state");
                return false;
            }
            if (mFragmentManager.getBackStackEntryCount() > 0) {
                mFragmentManager.popBackStack(
                        generateBackStackName(mBackStack.size(), mBackStack.peekLast()),
                        FragmentManager.POP_BACK_STACK_INCLUSIVE);
                mIsPendingBackStackOperation = true;
            } // else, we're on the first Fragment, so there's nothing to pop from FragmentManager
            mBackStack.removeLast();
            return true;
        }
    
        @NonNull
        @Override
        public StickyFragmentNavigator.Destination createDestination() {
            return new StickyFragmentNavigator.Destination(this);
        }
    
        @NonNull
        public Fragment instantiateFragment(@NonNull Context context,
                                            @SuppressWarnings("unused") @NonNull FragmentManager fragmentManager,
                                            @NonNull String className, @Nullable Bundle args) {
            return Fragment.instantiate(context, className, args);
        }
    
        @Nullable
        @Override
        public NavDestination navigate(@NonNull StickyFragmentNavigator.Destination destination, @Nullable Bundle args,
                                       @Nullable NavOptions navOptions, @Nullable Navigator.Extras navigatorExtras) {
            if (mFragmentManager.isStateSaved()) {
                Log.i(TAG, "Ignoring navigate() call: FragmentManager has already"
                        + " saved its state");
                return null;
            }
            String className = destination.getClassName();
            if (className.charAt(0) == '.') {
                className = mContext.getPackageName() + className;
            }
    
            final FragmentTransaction ft = mFragmentManager.beginTransaction();
    
            int enterAnim = navOptions != null ? navOptions.getEnterAnim() : -1;
            int exitAnim = navOptions != null ? navOptions.getExitAnim() : -1;
            int popEnterAnim = navOptions != null ? navOptions.getPopEnterAnim() : -1;
            int popExitAnim = navOptions != null ? navOptions.getPopExitAnim() : -1;
            if (enterAnim != -1 || exitAnim != -1 || popEnterAnim != -1 || popExitAnim != -1) {
                enterAnim = enterAnim != -1 ? enterAnim : 0;
                exitAnim = exitAnim != -1 ? exitAnim : 0;
                popEnterAnim = popEnterAnim != -1 ? popEnterAnim : 0;
                popExitAnim = popExitAnim != -1 ? popExitAnim : 0;
                ft.setCustomAnimations(enterAnim, exitAnim, popEnterAnim, popExitAnim);
            }
    
            String tag = Integer.toString(destination.getId());
            Fragment primaryNavigationFragment = mFragmentManager.getPrimaryNavigationFragment();
            if(primaryNavigationFragment != null)
                ft.hide(primaryNavigationFragment);
            Fragment destinationFragment = mFragmentManager.findFragmentByTag(tag);
            if(destinationFragment == null) {
                destinationFragment = instantiateFragment(mContext, mFragmentManager, className, args);
                destinationFragment.setArguments(args);
                ft.add(mContainerId, destinationFragment , tag);
            }
            else
                ft.show(destinationFragment);
    
            ft.setPrimaryNavigationFragment(destinationFragment);
    
            final @IdRes int destId = destination.getId();
            final boolean initialNavigation = mBackStack.isEmpty();
            // TODO Build first class singleTop behavior for fragments
            final boolean isSingleTopReplacement = navOptions != null && !initialNavigation
                    && navOptions.shouldLaunchSingleTop()
                    && mBackStack.peekLast() == destId;
    
            boolean isAdded;
            if (initialNavigation) {
                isAdded = true;
            } else if (isSingleTopReplacement) {
                // Single Top means we only want one instance on the back stack
                if (mBackStack.size() > 1) {
                    // If the Fragment to be replaced is on the FragmentManager's
                    // back stack, a simple replace() isn't enough so we
                    // remove it from the back stack and put our replacement
                    // on the back stack in its place
                    mFragmentManager.popBackStackImmediate(
                            generateBackStackName(mBackStack.size(), mBackStack.peekLast()), 0);
                    mIsPendingBackStackOperation = false;
                }
                isAdded = false;
            } else {
                ft.addToBackStack(generateBackStackName(mBackStack.size() + 1, destId));
                mIsPendingBackStackOperation = true;
                isAdded = true;
            }
            if (navigatorExtras instanceof FragmentNavigator.Extras) {
                FragmentNavigator.Extras extras = (FragmentNavigator.Extras) navigatorExtras;
                for (Map.Entry<View, String> sharedElement : extras.getSharedElements().entrySet()) {
                    ft.addSharedElement(sharedElement.getKey(), sharedElement.getValue());
                }
            }
            ft.setReorderingAllowed(true);
            ft.commit();
            // The commit succeeded, update our view of the world
            if (isAdded) {
                mBackStack.add(destId);
                return destination;
            } else {
                return null;
            }
        }
    
        @Override
        @Nullable
        public Bundle onSaveState() {
            Bundle b = new Bundle();
            int[] backStack = new int[mBackStack.size()];
            int index = 0;
            for (Integer id : mBackStack) {
                backStack[index++] = id;
            }
            b.putIntArray(KEY_BACK_STACK_IDS, backStack);
            return b;
        }
    
        @Override
        public void onRestoreState(@Nullable Bundle savedState) {
            if (savedState != null) {
                int[] backStack = savedState.getIntArray(KEY_BACK_STACK_IDS);
                if (backStack != null) {
                    mBackStack.clear();
                    for (int destId : backStack) {
                        mBackStack.add(destId);
                    }
                }
            }
        }
    
        @NonNull
        private String generateBackStackName(int backStackIndex, int destId) {
            return backStackIndex + "-" + destId;
        }
    
        private int getDestId(@Nullable String backStackName) {
            String[] split = backStackName != null ? backStackName.split("-") : new String[0];
            if (split.length != 2) {
                throw new IllegalStateException("Invalid back stack entry on the "
                        + "NavHostFragment's back stack - use getChildFragmentManager() "
                        + "if you need to do custom FragmentTransactions from within "
                        + "Fragments created via your navigation graph.");
            }
            try {
                // Just make sure the backStackIndex is correctly formatted
                Integer.parseInt(split[0]);
                return Integer.parseInt(split[1]);
            } catch (NumberFormatException e) {
                throw new IllegalStateException("Invalid back stack entry on the "
                        + "NavHostFragment's back stack - use getChildFragmentManager() "
                        + "if you need to do custom FragmentTransactions from within "
                        + "Fragments created via your navigation graph.");
            }
        }
    
        @SuppressWarnings("WeakerAccess") /* synthetic access */
        boolean isBackStackEqual() {
            int fragmentBackStackCount = mFragmentManager.getBackStackEntryCount();
            // Initial fragment won't be on the FragmentManager's back stack so +1 its count.
            if (mBackStack.size() != fragmentBackStackCount + 1) {
                return false;
            }
    
            // From top to bottom verify destination ids match in both back stacks/
            Iterator<Integer> backStackIterator = mBackStack.descendingIterator();
            int fragmentBackStackIndex = fragmentBackStackCount - 1;
            while (backStackIterator.hasNext() && fragmentBackStackIndex >= 0) {
                int destId = backStackIterator.next();
                try {
                    int fragmentDestId = getDestId(mFragmentManager
                            .getBackStackEntryAt(fragmentBackStackIndex--)
                            .getName());
                    if (destId != fragmentDestId) {
                        return false;
                    }
                } catch (NumberFormatException e) {
                    throw new IllegalStateException("Invalid back stack entry on the "
                            + "NavHostFragment's back stack - use getChildFragmentManager() "
                            + "if you need to do custom FragmentTransactions from within "
                            + "Fragments created via your navigation graph.");
                }
            }
    
            return true;
        }
    
        @NavDestination.ClassType(Fragment.class)
        public static class Destination extends NavDestination {
    
            private String mClassName;
    
            public Destination(@NonNull NavigatorProvider navigatorProvider) {
                this(navigatorProvider.getNavigator(StickyFragmentNavigator.class));
            }
    
            public Destination(@NonNull Navigator<? extends StickyFragmentNavigator.Destination> fragmentNavigator) {
                super(fragmentNavigator);
            }
    
            @CallSuper
            @Override
            public void onInflate(@NonNull Context context, @NonNull AttributeSet attrs) {
                super.onInflate(context, attrs);
                TypedArray a = context.getResources().obtainAttributes(attrs,
                        R.styleable.FragmentNavigator);
                String className = a.getString(R.styleable.FragmentNavigator_android_name);
                if (className != null) {
                    setClassName(className);
                }
                a.recycle();
            }
    
            @NonNull
            public final StickyFragmentNavigator.Destination setClassName(@NonNull String className) {
                mClassName = className;
                return this;
            }
    
            @NonNull
            public final String getClassName() {
                if (mClassName == null) {
                    throw new IllegalStateException("Fragment class was not set");
                }
                return mClassName;
            }
        }
    
        public static final class Extras implements Navigator.Extras {
            private final LinkedHashMap<View, String> mSharedElements = new LinkedHashMap<>();
    
            Extras(Map<View, String> sharedElements) {
                mSharedElements.putAll(sharedElements);
            }
    
            @NonNull
            public Map<View, String> getSharedElements() {
                return Collections.unmodifiableMap(mSharedElements);
            }
    
            public static final class Builder {
                private final LinkedHashMap<View, String> mSharedElements = new LinkedHashMap<>();
    
                @NonNull
                public StickyFragmentNavigator.Extras.Builder addSharedElements(@NonNull Map<View, String> sharedElements) {
                    for (Map.Entry<View, String> sharedElement : sharedElements.entrySet()) {
                        View view = sharedElement.getKey();
                        String name = sharedElement.getValue();
                        if (view != null && name != null) {
                            addSharedElement(view, name);
                        }
                    }
                    return this;
                }
    
                @NonNull
                public StickyFragmentNavigator.Extras.Builder addSharedElement(@NonNull View sharedElement, @NonNull String name) {
                    mSharedElements.put(sharedElement, name);
                    return this;
                }
    
                @NonNull
                public StickyFragmentNavigator.Extras build() {
                    return new StickyFragmentNavigator.Extras(mSharedElements);
                }
            }
        }
    }
    

    第 2 步:使用自定义标签

    现在打开您的 navigation.xml 文件,并使用您之前在 @Navigator.Name() 中提供的任何名称重命名与底部导航相关的 fragment 标签。

    <?xml version="1.0" encoding="utf-8"?>
    <navigation 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:id="@+id/mobile_navigation"
        app:startDestination="@+id/navigation_home">
    
        <sticky_fragment
            android:id="@+id/navigation_home"
            android:name="com.example.bottomnavigationlogic.ui.home.HomeFragment"
            android:label="@string/title_home"
            tools:layout="@layout/fragment_home" />
    
    </navigation>
    

    第 3 步:添加全局操作

    全局操作是一种从应用中的任何位置导航到目的地的方式。您可以使用可视化编辑器或直接使用 xml 来添加全局操作。使用以下设置对每个片段设置全局操作

    • 目的地:自己
    • popUpTo:自我
    • singleTop : true/checked

    这就是你的 navigation.xml 添加全局操作后的样子

    <?xml version="1.0" encoding="utf-8"?>
    <navigation 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:id="@+id/mobile_navigation"
        app:startDestination="@+id/navigation_home">
    
        <sticky_fragment
            android:id="@+id/navigation_home"
            android:name="com.example.bottomnavigationlogic.ui.home.HomeFragment"
            android:label="@string/title_home"
            tools:layout="@layout/fragment_home" />
    
        <sticky_fragment
            android:id="@+id/navigation_images"
            android:name="com.example.bottomnavigationlogic.ui.images.ImagesFragment"
            android:label="@string/title_images"
            tools:layout="@layout/fragment_images" />
    
        <sticky_fragment
            android:id="@+id/navigation_videos"
            android:name="com.example.bottomnavigationlogic.ui.videos.VideosFragment"
            android:label="@string/title_videos"
            tools:layout="@layout/fragment_videos" />
        <sticky_fragment
            android:id="@+id/navigation_songs"
            android:name="com.example.bottomnavigationlogic.ui.songs.SongsFragment"
            android:label="@string/title_songs"
            tools:layout="@layout/fragment_songs" />
        <sticky_fragment
            android:id="@+id/navigation_notifications"
            android:name="com.example.bottomnavigationlogic.ui.notifications.NotificationsFragment"
            android:label="@string/title_notifications"
            tools:layout="@layout/fragment_notifications" />
        <action
            android:id="@+id/action_global_navigation_home"
            app:destination="@id/navigation_home"
            app:launchSingleTop="true"
            app:popUpTo="@id/navigation_home" />
        <action
            android:id="@+id/action_global_navigation_notifications"
            app:destination="@id/navigation_notifications"
            app:launchSingleTop="true"
            app:popUpTo="@id/navigation_notifications" />
        <action
            android:id="@+id/action_global_navigation_songs"
            app:destination="@id/navigation_songs"
            app:launchSingleTop="true"
            app:popUpTo="@id/navigation_songs" />
        <action
            android:id="@+id/action_global_navigation_videos"
            app:destination="@id/navigation_videos"
            app:launchSingleTop="true"
            app:popUpTo="@id/navigation_videos" />
    </navigation>
    

    第 4 步:使用全局操作

    你写的时候

     NavigationUI.setupWithNavController (bottomNavigationView, navHostFragment.getNavController ());
    

    然后在setupWithNavController() 内部,NavigationUI 使用bottomNavigationView.setOnNavigationItemSelectedListener() 根据单击的菜单项的 ID 导航到正确的片段。它的默认行为就像我之前提到的那样。我们将向其中添加我们自己的实现,并使用全局操作来实现我们想要的背压行为。

    这就是你在MainActivity中的简单做法

     bottomNavigationView.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
                @Override
                public boolean onNavigationItemSelected(@NonNull MenuItem menuItem) {
                    int id = menuItem.getItemId();
                    if (menuItem.isChecked()) return false;
    
                    switch (id)
                    {
                        case R.id.navigation_home :
                            navController.navigate(R.id.action_global_navigation_home);
                            break;
                        case R.id.navigation_images :
                            navController.navigate(R.id.action_global_navigation_images);
                            break;
                        case R.id.navigation_videos :
                            navController.navigate(R.id.action_global_navigation_videos);
                            break;
                        case R.id.navigation_songs :
                            navController.navigate(R.id.action_global_navigation_songs);
                            break;
                        case R.id.navigation_notifications :
                            navController.navigate(R.id.action_global_navigation_notifications);
                            break;
                    }
                    return true;
    
                }
            });
    

    最后一步:将您的自定义导航器添加到 NavController

    在 MainActivity 中添加导航器,如下所示。确保您传递的是childFragmentManagerNavHostFragment

    navController.getNavigatorProvider().addNavigator(new StickyFragmentNavigator(this, navHostFragment.getChildFragmentManager(),R.id.nav_host_fragment));
    

    在此处也可以使用setGraph() 方法将导航图添加到NavController,如下所示。

    这是我的MainActivity步骤 4步骤 5

    之后的样子
    public class MainActivity extends AppCompatActivity {
        
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            BottomNavigationView navView = findViewById(R.id.nav_view);
           
            AppBarConfiguration appBarConfiguration = new AppBarConfiguration.Builder(
                    R.id.navigation_home, R.id.navigation_images, R.id.navigation_videos,R.id.navigation_songs,R.id.navigation_notifications)
                    .build();
            NavHostFragment navHostFragment = (NavHostFragment)getSupportFragmentManager().findFragmentById(R.id.nav_host_fragment);
            
            final NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment);
            navController.getNavigatorProvider().addNavigator(new StickyFragmentNavigator(this, navHostFragment.getChildFragmentManager(),R.id.nav_host_fragment));
            navController.setGraph(R.navigation.mobile_navigation);
            
            NavigationUI.setupActionBarWithNavController(this, navController, appBarConfiguration);
            NavigationUI.setupWithNavController(navView,navController);
            
            navView.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
                @Override
                public boolean onNavigationItemSelected(@NonNull MenuItem menuItem) {
                    int id = menuItem.getItemId();
                    if (menuItem.isChecked()) return false;
    
                    switch (id)
                    {
                        case R.id.navigation_home :
                            navController.navigate(R.id.action_global_navigation_home);
                            break;
                        case R.id.navigation_images :
                            navController.navigate(R.id.action_global_navigation_images);
                            break;
                        case R.id.navigation_videos :
                            navController.navigate(R.id.action_global_navigation_videos);
                            break;
                        case R.id.navigation_songs :
                            navController.navigate(R.id.action_global_navigation_songs);
                            break;
                        case R.id.navigation_notifications :
                            navController.navigate(R.id.action_global_navigation_notifications);
                            break;
                    }
                    return true;
    
                }
            });
    
        }
    
    }
    

    希望这会有所帮助。

    【讨论】:

    • 谢谢,实际上我想保存在我的片段中单击的 burrons,谢谢这个兄弟
    • 又发了一个问题,也许你能理解得更好
    • 我已经阅读了你的新问题,而且是一回事。您可以更新此问题以使其更具体,而不是创建新帖子。但无论如何,等我有空时,我会发布一个合适的解决方案。
    • @KyleMutta 抱歉让您等了一个多星期。实际上,我一直在寻找一个需要最少代码量并从导航组件库转移的解决方案。但最后我找到了一个。阅读更新的解决方案。它有点长,但值得一读。希望对您有所帮助。
    • 应该没那么难
    【解决方案2】:

    我不完全确定这是否是您正在寻找的答案,但如果您关心管理状态,那么管理状态的现代方式是使用称为视图模型的东西。视图模型是 MVVM 架构的一个组件。它们的目的是保存数据并将数据暴露给您的片段/活动以显示。使用导航架构,如果您在此视图模型中适当地存储与每个片段相关的数据,您的状态将保留在视图模型中。

    话虽如此,我个人建议研究 MVVM 架构以及专门查看模型。否则,保留状态的蛮力是在整个片段中使用savedInstance 状态并手动保存和恢复重要数据。

    链接: - Android View Model Component - Android architecture guide

    【讨论】:

      【解决方案3】:

      我认为您可能需要防止在单击底部导航视图项目两次时重新创建片段。 bottomNavigationView.setOnNavigationItemReselectedListener { /*Nothing to ignore reselection*/} NavigationUI.setupWithNavController (bottomNavigationView, navHostFragment.getNavController ()); 之后

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-10-03
        • 1970-01-01
        • 1970-01-01
        • 2020-08-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多