如何从FragmentManager中删除重复的条目?

时间:2017-07-21 14:29:55

标签: android android-fragments kotlin

我有一个BottomNavigationView的简单活动。我正在使用片段来实现不同页面的活动内容。

当用户按下后退按钮时,它应该返回到之前查看的页面。问题是,当您在页面(片段)之间反复切换时,会记录整个历史记录。举个例子:

A - > B - > A - > B - > C - > A - > ç

按下后退按钮会导致相反,但我希望这种行为(我在Instagram应用程序中注意到它):

C - > A - > B - >退出应用

所以每个片段在backstack中只应该有一个条目。我该怎么做呢?我是否从堆栈中删除了以前的片段事务?

使用FragmentManager完全可以吗?或者我必须实现自己的?

我对BottomNavigationView的活动:

class ActivityOverview : AppCompatActivity() {

    // Listener for BottomNavigationView
    private val mOnNavigationItemSelectedListener = BottomNavigationView.OnNavigationItemSelectedListener { item ->
        when (item.itemId) {
            R.id.navigation_home -> {
                // "Home" menu item pressed
                setActiveFragment(resources.getString(R.string.tag_fragment_home))
                return@OnNavigationItemSelectedListener true
            }
            R.id.navigation_dashboard -> {
                // "Dashboard" menu item pressed
                return@OnNavigationItemSelectedListener true
            }
            R.id.navigation_settings -> {
                // "Settings" menu item pressed
                setActiveFragment(resources.getString(R.string.tag_fragment_settings))
                return@OnNavigationItemSelectedListener true
            }
        }
        false
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_overview)

        navigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener)
        navigation.menu.findItem(R.id.navigation_home).setChecked(true)
        // Set initial fragment
        setActiveFragment(resources.getString(R.string.tag_fragment_home))
    }

    override fun onBackPressed() {
        // > 1 so initial fragment addition isn't removed from stack
        if (fragmentManager.backStackEntryCount > 1) {
            fragmentManager.popBackStack()
        } else {
            finish()
        }
    }

    // Update displayed fragment
    fun setActiveFragment(tag: String) {
        val fragment = if (fragmentManager.findFragmentByTag(tag) != null) {
            // Fragment is already initialized
            if (fragmentManager.findFragmentByTag(tag).isVisible) {
                // Fragment is visible already, don't add another transaction
                null
            } else {
                // Fragment is not visible, add transaction
                fragmentManager.findFragmentByTag(tag)
            }
        } else {
            // Fragment is not initialized yet
            when (tag) {
                resources.getString(R.string.tag_fragment_home) -> FragmentHome()
                resources.getString(R.string.tag_fragment_settings) -> FragmentSettings()
                else -> null
            }
        }

        if (fragment != null) {
            val transaction = fragmentManager.beginTransaction()
            transaction.replace(R.id.container_fragment, fragment, tag)
            transaction.addToBackStack(null)
            transaction.commit()
        }
    }
}

2 个答案:

答案 0 :(得分:0)

此时我很确定它不能使用FragmentManager,所以我创建了一个类来实现一个不允许重复的堆栈:

class NoDuplicateStack<T> {

    val stack: MutableList<T> = mutableListOf()
    val size: Int
        get() = stack.size

    // Push element onto the stack
    fun push(p: T) {
        val index = stack.indexOf(p)
        if (index != -1) {
            stack.removeAt(index)
        }
        stack.add(p)
    }

    // Pop upper element of stack
    fun pop(): T? {
        if (size > 0) {
            return stack.removeAt(stack.size - 1)
        } else {
            return null
        }
    }

    // Look at upper element of stack, don't pop it
    fun peek(): T? {
        if (size > 0) {
            return stack[stack.size - 1]
        } else {
            return null
        }
    }

}

然后我将这个课程整合到我的活动中:

class ActivityOverview : AppCompatActivity() {

    val fragmentsStack = NoDuplicateStack<String>()
    val fragmentHome = FragmentHome()
    val fragmentSettings = FragmentSettings()
    val fragmentHistory = FragmentHistory()

    // Listener for BottomNavigationView
    private val mOnNavigationItemSelectedListener = ...

    override fun onCreate(savedInstanceState: Bundle?) {
        ...
    }

    override fun onBackPressed() {
        if (fragmentsStack.size > 1) {
            // Remove current fragment from stack
            fragmentsStack.pop()
            // Get previous fragment from stack and set it again
            val newTag = fragmentsStack.pop()
            if (newTag != null) {
                setActiveFragment(newTag)
            }
        } else {
            finish()
        }
    }

    // Update displayed fragment
    fun setActiveFragment(tag: String) {
        val fragment = when (tag) {
            resources.getString(R.string.tag_fragment_home) -> fragmentHome
            resources.getString(R.string.tag_fragment_settings) -> fragmentSettings
            resources.getString(R.string.tag_fragment_history) -> fragmentHistory
            else -> null
        }

        if (fragment != null && !fragment.isVisible) {
            fragmentManager.beginTransaction()
                    .replace(R.id.container_fragment, fragment, tag)
                    .commit()
            fragmentsStack.push(tag)
        }
    }
}

答案 1 :(得分:0)

我也遇到了同样的问题,我这样做是使用系统堆栈

   val totalFragments = supportFragmentManager.backStackEntryCount

            if (totalFragments != 0) {
                val removed = supportFragmentManager.getBackStackEntryAt(totalFragments - 1)
                poppedFragments.add(removed.name!!)

                for (idx in totalFragments - 1  downTo 0) {
                    val fragment = supportFragmentManager.getBackStackEntryAt(idx)
                    if (!poppedFragments.contains(fragment.name)) {
                        supportFragmentManager.popBackStack(fragment.name, 0)
                        return
                    }
                }

                finish()
                return
            }

            super.onBackPressed()

,然后在启动片段时将其添加

    if (poppedFragments.contains(tag)) {
            poppedFragments.remove(tag)
        }