Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/218.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 碎片事务隐藏/显示不';我有时不工作_Android_Android Fragments_Kotlin_Fragmentmanager - Fatal编程技术网

Android 碎片事务隐藏/显示不';我有时不工作

Android 碎片事务隐藏/显示不';我有时不工作,android,android-fragments,kotlin,fragmentmanager,Android,Android Fragments,Kotlin,Fragmentmanager,我有一个带有底部导航选项卡的活动,它正在更改其中的片段。当我在这些选项卡上来回单击时,它会在某个点停止工作。代码执行得很好,因为我在其中放了一些日志。但这些片段并没有被切换 代码在kotlin中,但它相当直接 fun showTabFragment(tag: String) { val currentFragment: Fragment? = supportFragmentManager.fragments?.lastOrNull() var fragment =

我有一个带有底部导航选项卡的活动,它正在更改其中的片段。当我在这些选项卡上来回单击时,它会在某个点停止工作。代码执行得很好,因为我在其中放了一些日志。但这些片段并没有被切换

代码在kotlin中,但它相当直接

fun showTabFragment(tag: String) {
        val currentFragment: Fragment? = supportFragmentManager.fragments?.lastOrNull()
        var fragment = supportFragmentManager.findFragmentByTag(tag)
        val fragmentExists = fragment != null
        if (fragment == null) {
            when (tag) {
                TAG_LOGBOOK -> fragment = LogbookFragment()
                TAG_RECIPES -> fragment = RecipesFragment()
                TAG_PROFILE -> fragment = ProfileFragment()
                else -> fragment = MeetingPlacesFragment()
            }
        }

        val transaction = supportFragmentManager.beginTransaction()

        if (currentFragment != null) {
            Log.i("jacek", "hiding " + currentFragment.javaClass.simpleName)
            transaction.hide(currentFragment)
        }

        if (fragmentExists) {
            Log.i("jacek", "showing " + fragment.javaClass.simpleName)
            transaction.show(fragment)
        } else {
            Log.i("jacek", "adding " + fragment.javaClass.simpleName)
            transaction.add(R.id.container, fragment, tag)
        }

        transaction.commit()
    }
碎片很重。我会尝试一些轻量级的,但在我看来这应该不是一个问题。还有什么我可以试试的吗

我正在使用最新的支持库-25.2.0
此外,我对替换片段不感兴趣,因为重点是添加交叉淡入淡出动画而不重新创建它们

这里的问题是,即使您隐藏了“当前”片段,内存中也加载了其他片段,这会导致不一致的行为

您应该能够通过隐藏除要显示的片段之外的所有片段来修复此问题

多亏了这个答案

例如:


类似地,您必须为displayFragmentB()和displayFragmentC()编写函数。

@Ali的答案很好,但是想象一下如果您有5个片段。这是显示/隐藏片段的另一种方式:

    // in BaseFragment
    public abstract String getTAG();

    //in FragmentA, FragmentB and FragmentC
    public String getTAG(){
        return TAG;
    }

    //Activity containing the fragments
    //android.support.v4.app.Fragment;    
    private FragmentA fragmentA; //inherited BaseFragment
    private FragmentB fragmentB; //inherited BaseFragment
    private FragmentC fragmentC; //inherited BaseFragment
    private ConcurrentHashMap<String,BaseFragment> mapOfAddedFragments = new ConcurrentHashMap<>();


    /**
     * Displays fragment A
     */
    private void displayFragmentA() {
        displayFragment(fragmentA)
    }

    /**
     * Displays  fragment B
     */
    private void displayFragmentB() {
       displayFragment(fragmentB)
    }

    /**
     * Displays  fragment C
     */
    private void displayFragmentC() {
        displayFragment(fragmentC)
    }


     /**
     * Loads a fragment using show a fragment
     * @param fragment
     */
    private void displayFragment(BaseFragment fragment){
        if(!mapOfAddedFragments.containsKey(fragment.getTAG()))
            mapOfAddedFragments.put(fragment.getTAG(), fragment);

        showFragment(fragment.getTAG(), R.id.containerBody);
    }

    /**
     * Displays a fragment and hides all the other ones
     * @param fragmentTag is the tag of the fragment we want to display
     */
    private void showFragment(String fragmentTag, @IdRes int containerViewId){
        FragmentTransaction ft = this.getSupportFragmentManager().beginTransaction();
        BaseFragment fragment = null;

        fragment = mapOfAddedFragments.get(fragmentTag);
        if(fragment != null) {
            if (fragment.isAdded())
                ft.show(fragment);
            else { //fragment needs to be added to the frame container
                ft.add(containerViewId, fragment, fragment.getTAG());
            }
        }
        else //the chosen fragment doesn't exist
            return;

        //we hide the other fragments
        for (ConcurrentHashMap.Entry<String, BaseFragment> entry : mapOfAddedFragments.entrySet()){
            if(!entry.getKey().equals(fragmentTag)){
                BaseFragment fragmentTemp = entry.getValue();
                // Hide the other fragments
                if(fragmentTemp != null)
                    if(fragmentTemp.isAdded())
                        ft.hide(fragmentTemp);
            }
        }

        //commit changes
        ft.commit();
    }
根据Shujaat Ali Khan的问题编辑:

BaseFragment扩展了support4片段:

public abstract class BaseFragment extends Fragment {
    public abstract String getTAG();
    //whatever we can add to be inherited
}
片段a例如:

public class FragmentA extends BaseFragment {
    // Store instance variables
    private static final String ARG_PARAM1 = "param1";
    private static final String ARG_PARAM2 = "param2";

    private String mParam1;
    private String mParam2;

    public static final String TAG = "FragmentA";

    // newInstance constructor for creating fragment with arguments
    public static FragmentA newInstance(String param1, String param2) {
        FragmentA fragment = new FragmentA();
        Bundle args = new Bundle();
        args.putString(ARG_PARAM1, param1);
        args.putString(ARG_PARAM2, param2);
        fragment.setArguments(args);
        return fragment;
    }

    // Store instance variables based on arguments passed
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (getArguments() != null) {
            mParam1 = getArguments().getString(ARG_PARAM1);
            mParam2 = getArguments().getString(ARG_PARAM2);
        }
    }

    // Inflate the view for the fragment based on layout XML
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragmentA, container, false);
        return view;
    }

    //other lifecycle methods

    @Override
    public String getTAG() {
        return TAG;
    }
}

最后,
R.id.containerBody
是包含这些片段的活动中包含片段的FrameLayout的id。

您需要重用要隐藏或显示的片段的相同实例

private fun replaceFragment(fragment: Fragment) {
    supportFragmentManager.beginTransaction().apply {
        if (fragment.isAdded) {
            show(fragment)
        } else {
            add(R.id.fmFragmentContainer, fragment)
        }

        supportFragmentManager.fragments.forEach {
            if (it != fragment && it.isAdded) {
                hide(it)
            }
        }
    }.commit()
}

在同一事务中的相同片段上调用
hide()
然后调用
show()
可能会出现问题?就像当
currentFragment
引用与
fragment
相同的片段时一样,这在这里肯定会发生。说到这里,我认为在
supportFragmentManager.fragments
列表中声明最后一个片段将是最后显示的片段(而不是最近添加的片段)是错误的。您应该遍历所有
片段
并搜索一个
isVisible()
为true的片段,或者只存储最后显示的片段标记,稍后再查找它。您是否可以显示至少FragmentA类的实现?因为我是初学者,所以我对NewInstance()方法的定义感到困惑。@ShujaatAliKhan我刚刚编辑了答案以添加一个示例。
public class FragmentA extends BaseFragment {
    // Store instance variables
    private static final String ARG_PARAM1 = "param1";
    private static final String ARG_PARAM2 = "param2";

    private String mParam1;
    private String mParam2;

    public static final String TAG = "FragmentA";

    // newInstance constructor for creating fragment with arguments
    public static FragmentA newInstance(String param1, String param2) {
        FragmentA fragment = new FragmentA();
        Bundle args = new Bundle();
        args.putString(ARG_PARAM1, param1);
        args.putString(ARG_PARAM2, param2);
        fragment.setArguments(args);
        return fragment;
    }

    // Store instance variables based on arguments passed
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (getArguments() != null) {
            mParam1 = getArguments().getString(ARG_PARAM1);
            mParam2 = getArguments().getString(ARG_PARAM2);
        }
    }

    // Inflate the view for the fragment based on layout XML
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragmentA, container, false);
        return view;
    }

    //other lifecycle methods

    @Override
    public String getTAG() {
        return TAG;
    }
}
private fun replaceFragment(fragment: Fragment) {
    supportFragmentManager.beginTransaction().apply {
        if (fragment.isAdded) {
            show(fragment)
        } else {
            add(R.id.fmFragmentContainer, fragment)
        }

        supportFragmentManager.fragments.forEach {
            if (it != fragment && it.isAdded) {
                hide(it)
            }
        }
    }.commit()
}