Android 处理隐藏和显示的反压片段

Android 处理隐藏和显示的反压片段,android,android-fragments,Android,Android Fragments,我有一个活动,它承载三个片段,我可以使用底部导航视图在片段之间切换。我用来在片段之间切换的机制是使用显示和隐藏片段事务的功能,而不是替换碎片事务的功能。我这样做是因为我希望某些网络操作只执行一次,并且只对布局充气一次 使用此机制所面临的问题是,当我从任何片段启动另一个活动,然后点击后退按钮时,底部导航视图的selectedItem与显示的片段不匹配 虽然我能解决这个问题,但我觉得效率较低。程序是,每当我在切换片段时单击底部导航中的选项卡时,我都会给它一些预先指定的数字,并保存在一个静态变量(X)

我有一个活动,它承载三个
片段
,我可以使用
底部导航视图
片段
之间切换。我用来在
片段
之间切换的机制是使用
显示
隐藏
片段事务
的功能,而不是
替换
碎片事务的功能
。我这样做是因为我希望某些网络操作只执行一次,并且只对布局充气一次

使用此机制所面临的问题是,当我从任何
片段
启动另一个
活动
,然后点击后退按钮时,
底部导航视图
的selectedItem与显示的
片段
不匹配

虽然我能解决这个问题,但我觉得效率较低。程序是,每当我在切换
片段时单击
底部导航中的选项卡时,我都会给它一些预先指定的数字,并保存在一个静态变量(
X
)中,每当我单击
OnResume()中的后退按钮时
托管活动的方法我使用
X
制作了一个开关盒块,在开始新活动之前知道哪个
Fragment
可见,然后最后制作三个
FragmentTransaction
,以显示和隐藏所需的
Fragment

protected void onResume() {
        super.onResume();


        if(selectedId!=63){
           switch(selectedId){
               case 0:if(bottomNavigationView.getSelectedItemId()==R.id.navigation_home){handleHomeFragmentVisibility();}
                   break;
               case 1:if(bottomNavigationView.getSelectedItemId()==R.id.navigation_dashboard)
               {handleDashboardFragmentVisibility();}
                   break;
               case 2:if(bottomNavigationView.getSelectedItemId()==R.id.navigation_notifications)
               {handleNotificationFragmentVisibility();}
                   break;
           }

        }
我觉得使用三个
片段事务
的成本很高,我正在寻找一些有效的方法。如果你知道的话,你能告诉我一个吗

public void handleHomeFragmentVisibility(){
        FragmentManager fragmentManager=  getSupportFragmentManager();
        if (fragmentManager.findFragmentByTag("home") != null) {
            //if the fragment exists, show it.
            fragmentManager.beginTransaction().show(fragmentManager.findFragmentByTag("home")).commit();
        } else {
            //if the fragment does not exist, add it to fragment manager.


            Log.e(TAG,"homeFragmentAdded");
            fragmentManager.beginTransaction().add(R.id.container, new HomeFragment(), "home").commit();
        }
        if (fragmentManager.findFragmentByTag("dashboard") != null) {
            //if the other fragment is visible, hide it.
            fragmentManager.beginTransaction().hide(fragmentManager.findFragmentByTag("dashboard")).commit();
        }
        if (fragmentManager.findFragmentByTag("requests") != null) {
            //if the other fragment is visible, hide it.
            fragmentManager.beginTransaction().hide(fragmentManager.findFragmentByTag("requests")).commit();
        }

    }

    public void handleDashboardFragmentVisibility(){
        FragmentManager fragmentManager=  getSupportFragmentManager();
        if (fragmentManager.findFragmentByTag("dashboard") != null) {
            //if the fragment exists, show it.
            fragmentManager.beginTransaction().show(fragmentManager.findFragmentByTag("dashboard")).commit();
        } else {
            //if the fragment does not exist, add it to fragment manager.

            fragmentManager.beginTransaction().add(R.id.container, new DashboardFragment(), "dashboard").commit();
        }
        if (fragmentManager.findFragmentByTag("home") != null) {
            //if the other fragment is visible, hide it.
            fragmentManager.beginTransaction().hide(fragmentManager.findFragmentByTag("home")).commit();
        }
        if (fragmentManager.findFragmentByTag("requests") != null) {
            //if the other fragment is visible, hide it.
            fragmentManager.beginTransaction().hide(fragmentManager.findFragmentByTag("requests")).commit();
        }

    }
    public void handleNotificationFragmentVisibility(){
        FragmentManager fragmentManager=  getSupportFragmentManager();
        if (fragmentManager.findFragmentByTag("requests") != null) {
            //if the fragment exists, show it.
            fragmentManager.beginTransaction().show(fragmentManager.findFragmentByTag("requests")).commit();
        } else {
            //if the fragment does not exist, add it to fragment manager.

            fragmentManager.beginTransaction().add(R.id.container, new NotificationFragment(), "requests").commit();
        }
        if (fragmentManager.findFragmentByTag("home") != null) {
            //if the other fragment is visible, hide it.
            fragmentManager.beginTransaction().hide(fragmentManager.findFragmentByTag("home")).commit();
        }
        if (fragmentManager.findFragmentByTag("dashboard") != null) {
            //if the other fragment is visible, hide it.
            fragmentManager.beginTransaction().hide(fragmentManager.findFragmentByTag("dashboard")).commit();
        }
    }

 bottomNavigationView.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {

            @Override
            public boolean onNavigationItemSelected(@NonNull MenuItem item) {
                FragmentManager fragmentManager = getSupportFragmentManager();
                switch (item.getItemId()) {
                    case R.id.navigation_home:
                        selectedId=0;
                       handleHomeFragmentVisibility();
                        break;
                    case R.id.navigation_dashboard:
                    selectedId=1;
                     handleDashboardFragmentVisibility();

                        break;
                    case R.id.navigation_notifications:
                   selectedId=2;
                      handleNotificationFragmentVisibility();
                        break;

                }

                return true;
            }
        });

关于代码的第一个注意事项:避免使用样板文件!只编写一个方法而不是三个,并使用类型为
handleFragmentVisibility(字符串显示、字符串hide1、字符串hide2、int容器)的签名
。如果要显示的片段为
null
,请通过测试
show
,将其实例化,如下所示:

Fragment newFragment = (show == "home") ? new HomeFragment() : (show == "dashboard") ? new DashboardFragment() : new NotificationFragment();
但是,您的任何片段都不应通过隐藏(请自己检查)而获得
null
,因为您不会
从活动中删除它们或
用其他片段替换它们。除了使用
show
hide
之外,还可以使用
attach
detach
,这两组方法都保持状态。我没有看到效率问题,您确实需要调用三个
FragmentTransaction
s。只能用较少的代码完成:

public void handleFragmentVisibility(String show, String hide1, String hide2){
    FragmentManager fragmentManager = getSupportFragmentManager();
    fragmentManager.beginTransaction().show(fragmentManager.findFragmentByTag(show)).commit();
    fragmentManager.beginTransaction().hide(fragmentManager.findFragmentByTag(hide1)).commit();
    fragmentManager.beginTransaction().hide(fragmentManager.findFragmentByTag(hide2)).commit();
    }

请注意,尽管此方法在隐藏或分离片段时保持片段的状态,但其他事件(如方向更改)仍然需要您在保存InstanceState(Bundle savedInstanceState)

中保存状态,您不清楚自己在问什么。我理解,在开始一项新活动后,您希望能够返回到旧活动并恢复状态。为此,您需要在活动包中保存一个变量,并在返回后将其恢复。例如,它可以是片段列表的索引。不需要调用多个
FragmentTransaction
,并且在
onResume()
代码中不调用任何事务。当一个switch语句就足够时,使用if-switch-if-cascade并不是特别有效,但也不太昂贵。@KalaBalik我使用三个事务,因为我需要显示一个片段并隐藏另外两个片段,否则两个或三个片段将显示为相互重叠,这是无意的。我在
if
块inisde
开关中调用的每个函数都有三个事务,每个事务都显示和隐藏所需的片段。使用
setOnNavigationItemSelectedListener
将大大简化这一过程。您是否遇到性能缓慢的问题?您的操作方式没有问题。如果我是你,我会保持原样,我知道一个简单函数需要很多代码。