如果通过XML添加,则替换Fragment时没有生命周期

时间:2017-02-03 05:39:36

标签: android android-fragments

我遇到的问题是,替换通过XML添加的初始片段不会调用任何破坏生命周期的回调,例如onDetach()onDestroy()onDestroyView()onStop()等。这是一个问题,因为我想在onDetach()中执行操作。

这是我的设置。正如谷歌开发者文档所说的那样(https://developer.android.com/guide/components/fragments.html),我创建了一个带有片段的布局,activity_main.xml。

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:ads="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@drawable/sky_2"
    tools:context=".activity.MainActivity"
    tools:ignore="UselessParent,contentDescription">

    <fragment
        android:id="@+id/frag_container"
        android:name="com.example.GameFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

    <include layout="@layout/footer" />
</RelativeLayout>

我的MainActivity中引用了此布局。作为FYI,包含的页脚只是四个表示选项卡的ImageView。

   @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        if (!Utils.checkIfNull(findViewById(R.id.frag_container))) {

            // if we're being restored from a previous state,
            // then we don't need to do anything and should return or else
            // we could end up with overlapping fragments.
            if (!Utils.checkIfNull(savedInstanceState)) {
                return;
            }
        }

        // initialize views
        initializeViews();
    }

当我的应用启动时,它会按预期启动我的GameFragment。文件说明

  

当系统创建此活动布局时,它会实例化每个活动布局   在布局中指定的片段并调用onCreateView()方法   对于每一个,检索每个片段的布局。系统插入   片段返回的视图直接代替   元件。

我的GameFragment onCreateView()回调确实被调用,所有内容都被初始化,我能够执行所有功能。当我更改标签时会出现问题。我通过用新的片段替换当前片段来更改标签。这是我正在使用的功能。

public void addFragmentReplace(int containerId, @NonNull Fragment fragment) {
    // check if the fragment has been added already
    Fragment temp = mFragmentManager.findFragmentByTag(fragment.getClass().getSimpleName());
    if (!Utils.checkIfNull(temp) && temp.isAdded()) {
        return;
    }

    // replace fragment and transition with animation
    try {
        if (!Utils.isStringEmpty(getTopFragment().getTag()) && getTopFragment().isAdded()) {
            // pop back stack
            popBackStack();
        }
        mFragmentManager.beginTransaction().replace(containerId, fragment,
                fragment.getClass().getSimpleName()).addToBackStack(null).commit();
    } catch (IllegalStateException e) {
        e.printStackTrace();
        mFragmentManager.beginTransaction().replace(containerId, fragment,
                fragment.getClass().getSimpleName()).addToBackStack(null)
                .commitAllowingStateLoss(); // used as last resort
    }
}

我通过简单地说

来调用该函数
addFragmentReplace(R.id.frag_container, new NewsFragment());

我注意到的行为是,当从初始选项卡更改为任何其他选项卡时,我没有收到任何回调。一旦我返回到初始选项卡并更改为任何其他选项卡,一切都很完美。我试着监控我的backstackcount以进一步了解可能发生的事情。在我的MainActivity onCreate()方法中,我记录了backstackcount,它出现为0,即使我在第一次启动我的应用程序后可以清楚地看到GameFragment。当我更改标签时,我的backstackcount变为1,无论我因addFragmentReplace()方法更改标签多少次,它都保持为1。我不确定当通过XML添加片段时会发生什么,但我认为这样做或者我的替换功能不正确。提前谢谢!

1 个答案:

答案 0 :(得分:0)

我了解到如果您通过XML添加片段,则无法动态删除/替换。我通过编程方式完成所有事情来解决我的问题首先,在MainActivity中添加GameFragment

  @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // Check that the activity is using the layout version with
        // the fragment_container FrameLayout
        if (!Utils.checkIfNull(findViewById(R.id.frag_container))) {

            // However, if we're being restored from a previous state,
            // then we don't need to do anything and should return or else
            // we could end up with overlapping fragments.
            if (!Utils.checkIfNull(savedInstanceState)) {
                return;
            }

            addFragment(R.id.frag_container, new GameFragment());
        }

        // initialize views
        initializeViews();
    }

然后我将XML更改为具有FrameLayout容器,而不是片段1。

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:ads="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@drawable/sky_2"
    tools:context=".activity.MainActivity"
    tools:ignore="UselessParent,contentDescription">

    <FrameLayout
        android:id="@+id/frag_container"
        android:name="com.example.GameFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

    <include layout="@layout/footer" />
</RelativeLayout>