【问题标题】:The specified child already has a parent. Fragment on back press指定的孩子已经有一个父母。背压上的片段
【发布时间】:2019-05-07 08:15:36
【问题描述】:

我知道这个问题似乎被问到并得到了回答,但事实并非如此。因为我还没有找到解决方案。

我有很多片段的 Activity。并且我存储了所有的转换历史(可以通过后退按 LIFO 顺序返回每个片段 - 因为每个片段都添加到后堆栈)

我想达到下一个功能: 当我按下返回时 - 不能重新创建底部片段的视图。

下一个

1) 使用 android 导航组件和过渡,如

fun navigate(@IdRes resId: Int, bundle: Bundle? = null, navOptions: NavOptions? = null, sharedElements: List<View>? = null) {
        navController.navigate(resId, bundle, navOptions, sharedElements?.let {
            if (it.isEmpty()) null else
                FragmentNavigatorExtras(
                        *it.map { view -> Pair(view, view.transitionNameCompat.safe) }
                                .filter { pair -> pair.second.isNotEmpty() }
                                .toTypedArray()
                )
        })
    }

其中 idRes 是目标 id(不是转换 id)

2) 在片段中保存内容视图,并在 onCreateView 视图方法中将其与父级分离。因为getView()返回null,甚至片段出现在后栈中。

private var contentView: View? = null

override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? =
        prepareView(contentView) ?: createView(inflater, container)

private fun prepareView(view: View?): View? {
    val parent = view?.parent
    val viewGroup = parent as? ViewGroup
    viewGroup?.removeView(view)
    return view
}

protected open fun createView(inflater: LayoutInflater, container: ViewGroup?): View? {
    val layout = layout()
    if (layout == -1)
        throw IllegalArgumentException("You need to override \"layout()\" fun or override \"createView\" fun")
    return inflater.inflate(layout(), container, false)
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    if (contentView == null) {
        onFirstInitialization(view, savedInstanceState)
    } else {
        onNextInitialization(view, savedInstanceState)
    }
    onEachInitialization(view, savedInstanceState)
    contentView = view
}

只有当我转移到下一个片段并快速按“返回”时,我才会遇到异常!在正常模式下一切正常。

例外:

 java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.
        at android.view.ViewGroup.addViewInner(ViewGroup.java:5050)
        at android.view.ViewGroup.addView(ViewGroup.java:4881)
        at android.view.ViewGroup.addView(ViewGroup.java:4821)
        at android.view.ViewGroup.addView(ViewGroup.java:4794)
        at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManagerImpl.java:890)
        at androidx.fragment.app.FragmentManagerImpl.addAddedFragments(FragmentManagerImpl.java:2092)
        at androidx.fragment.app.FragmentManagerImpl.executeOpsTogether(FragmentManagerImpl.java:1866)
        at androidx.fragment.app.FragmentManagerImpl.removeRedundantOperationsAndExecute(FragmentManagerImpl.java:1822)
        at androidx.fragment.app.FragmentManagerImpl.execPendingActions(FragmentManagerImpl.java:1723)
        at androidx.fragment.app.FragmentManagerImpl.dispatchStateChange(FragmentManagerImpl.java:2624)
        at androidx.fragment.app.FragmentManagerImpl.dispatchActivityCreated(FragmentManagerImpl.java:2580)
        at androidx.fragment.app.Fragment.performActivityCreated(Fragment.java:2571)
        at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManagerImpl.java:907)
        at androidx.fragment.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManagerImpl.java:1235)
        at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManagerImpl.java:1301)
        at androidx.fragment.app.FragmentManagerImpl.dispatchStateChange(FragmentManagerImpl.java:2620)
        at androidx.fragment.app.FragmentManagerImpl.dispatchActivityCreated(FragmentManagerImpl.java:2580)
        at androidx.fragment.app.FragmentController.dispatchActivityCreated(FragmentController.java:246)
        at androidx.fragment.app.FragmentActivity.onStart(FragmentActivity.java:541)
        at androidx.appcompat.app.AppCompatActivity.onStart(AppCompatActivity.java:201)
        at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1470)
        at android.app.Activity.performStart(Activity.java:7176)
        at android.app.ActivityThread.handleStartActivity(ActivityThread.java:3086)
        at android.app.servertransaction.TransactionExecutor.performLifecycleSequence(TransactionExecutor.java:180)
        at android.app.servertransaction.TransactionExecutor.cycleToPath(TransactionExecutor.java:165)
        at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:142)
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:70)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1926)
        at android.os.Handler.dispatchMessage(Handler.java:106)
        at android.os.Looper.loop(Looper.java:193)
        at android.app.ActivityThread.main(ActivityThread.java:6923)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:537)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)

我可以通过将prepareView 到onDestroyView 生命周期方法来解决这个问题,一切正常,但它会产生内存泄漏:我发现 - 当视图在onDestroyView 之后没有父级时,onDestroy 永远不会即使在后按之后,调用和片段也会保留在内存中。

你可以说“嘿,伙计,别着急,慢慢地使用你的应用程序,永远不会抛出异常,就像你说的那样。但是生产中的应用程序和我遇到了这个错误的崩溃”:(我该如何处理案例?

更新: 我研究了一下,发现了一些东西。仅当视图未与窗口分离时才引发异常。并且视图仅在新片段打开后 300-400 毫秒后从窗口分离

【问题讨论】:

    标签: android android-fragments navigation


    【解决方案1】:

    是的!这是真的。您不能再次创建它的对象,因为它有一个父对象。您可能没有注意到的主要问题是,每当您再次调用片段时,就会调用 onCreateView()。

    因此,我建议您将代码从onCreateView() 移至片段的onCreate() 方法。

    我也遇到过这类问题。因此,在 onCreate() 方法中扩展您的视图并在 onCreateView() 方法中返回主视图。

    【讨论】:

    • 我没听懂。如果我在 onCreate 中创建视图,然后在 onCreateView 中返回它-它将有一个父级。当我导航回来时,它也会产生异常。
    • 不!查看错误“您必须先在孩子的父母上调用 removeView()”,这意味着 onCreateView() 再次膨胀新对象。所以,尝试在 onCreate() 中充气。
    • 兄弟,只是尝试理解 onCreateView() 膨胀 convertView 的新对象!
    • 嗯。但在这种情况下我必须重新加载视图内容,对吗?
    • 如果你在 onCreate() 中膨胀了这个对象,那么它每次都会在 onCreateView() 中使用相同的对象。因此,创建对象不会有任何麻烦。祝你好运:)
    猜你喜欢
    • 2012-03-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-21
    • 2021-06-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多