android - 处理屏幕旋转上的 fragment 重复(带有示例代码)

标签 android android-fragments android-listfragment android-fragmentactivity android-framelayout

有一些类似的答案,但不是针对这种情况。


我的情况很简单。

我有一个具有两种不同布局的 Activity,一种是纵向布局,另一种是横向布局。

纵向中,我使用<FrameLayout>并添加 Fragment 动态地

横向中,我使用<fragment>所以 Fragment静态的(其实这并不重要)

它首先从Portrait开始,然后我添加了Fragment通过简单地:

ListFrag listFrag = new ListFrag();
getSupportFragmentManager().beginTransaction()
        .replace(R.id.FragmentContainer, listFrag).commit();

哪里ListFrag extends ListFragment .

然后我旋转屏幕。 我发现 listFrag 正在横向模式下重新创建。 (其中我注意到 onCreate() 方法被非空 Bundle 再次调用)

我尝试使用 setRetainInstance(false)就像@NPike 在 this post 中所说的那样.但是 getRetainInstance()已经是false默认。它没有像我预期的那样做 the docs说。谁能解释一下?


我正在处理的 fragment 是一个 ListFragment , 这确实 setListAdapter()onCreate() .所以 if (container == null) return null; method不能在这里使用。 (或者我不知道如何申请)。

我从 this post 得到了一些提示.我应该使用 if (bundle != null) setListAdapter(null); else setListAdapter(new ...); 吗?在我的 ListFragment ?但是有没有更好的方法在 fragment 被销毁/分离时确实移除/删除 fragment ,而不是在 fragment 创建时进行? (所以作为 if (container == null) return null; 方法)


编辑:

我发现唯一巧妙的方法是做 getSupportFragmentManager().beginTransaction().remove(getSupportFragmentManager().findFragmentById(R.id.FragmentContainer)).commit();onSaveInstanceState() .但它会引发另一个问题。

  1. 当屏幕被部分遮挡时,如弹出 WhatsApp 或 TXT 对话框, fragment 也会消失。 (这是相对较小的,只是视觉问题)

  2. 当屏幕旋转时,Activity 被完全销毁并重新创建。所以我可以重新添加 onCreate(Bundle) 中的 fragment 或 onRestoreInstanceState(Bundle) .但是在 (1) 的情况下,以及切换 Activity ,onCreate(Bundle) 都不是也不onRestoreInstanceState(Bundle)当用户回到我的 Activity 时将被调用。我无处可重新创建 Activity(并从 Bundle 检索数据)。

对不起,我没有说清楚,我已经有了决定,getSupportFragmentManager()...replace(...).commit();线仅在纵向模式下运行。


示例代码

我提取了简单的代码,以便更好地说明情况:)

MainActivity.java

package com.example.fragremovetrial;

import android.os.Bundle;
import android.support.v4.app.FragmentActivity;

public class MainActivity extends FragmentActivity {

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

        if (findViewById(R.id.FragmentContainer) != null) {
            System.out.println("-- Portrait --");       // Portrait
            ListFrag listFrag = new ListFrag();
            getSupportFragmentManager().beginTransaction()
                    .replace(R.id.FragmentContainer, listFrag).commit();
        } else {
            System.out.println("-- Landscape --");      // Landscape
        }
    }

    @Override
    protected void onResume() {
        super.onResume();
        if (findViewById(R.id.FragmentContainer) != null) {
            System.out.println("getRetainInstance = " +
                    getSupportFragmentManager().findFragmentById(R.id.FragmentContainer).getRetainInstance());
        }
    }
}

layout/activity_main.xml

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/FragmentContainer"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" />

layout-land/activity_main.xml (无所谓)

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >
</LinearLayout>

ListFrag.java

package com.example.fragremovetrial;

import android.os.Bundle;
import android.support.v4.app.ListFragment;
import android.widget.ArrayAdapter;

public class ListFrag extends ListFragment {
    private String[] MenuItems = { "Content A", "Contnet B" };

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        System.out.println("ListFrag.onCreate(): " + (savedInstanceState == null ? null : savedInstanceState));

        setListAdapter(new ArrayAdapter<String>(getActivity(), android.R.layout.simple_list_item_1, MenuItems));
    }
}

注意我得到了以下内容

调试消息

-- Portrait --
ListFrag.onCreate(): null
getRetainInstance = false

(rotate Port -> Land)

ListFrag.onCreate(): Bundle[{android:view_state=android.util.SparseArray@4052dd28}]
-- Landscape --
Previously focused view reported id 16908298 during save, but can't be found during restore.

(rotate Land -> Port)

ListFrag.onCreate(): Bundle[{android:view_state=android.util.SparseArray@405166c8}]
-- Portrait --
ListFrag.onCreate(): null
getRetainInstance = false

(rotate Port -> Land)

ListFrag.onCreate(): Bundle[{android:view_state=android.util.SparseArray@4050fb40}]
-- Landscape --
Previously focused view reported id 16908298 during save, but can't be found during restore.

(rotate Land -> Port)

ListFrag.onCreate(): Bundle[{android:view_state=android.util.SparseArray@40528c60}]
-- Portrait --
ListFrag.onCreate(): null
getRetainInstance = false

随着屏幕不断旋转,创建的 fragment 数量不会无限增加,我无法解释。 (请帮忙)

最佳答案

处理这个问题的正确方法是在你的 onCreate() 中添加以下内容

if (savedInstanceState == null) {
     // Do fragment transaction.
}

关于android - 处理屏幕旋转上的 fragment 重复(带有示例代码),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15496362/

相关文章:

android - 恢复 Activity 时重叠 fragment

android - Activity 结束时更新 ListFragment

android - 使用 Canvas 和 canvas.scale(Scale, Scale) 的图像质量问题;

java - 我的 fragment Activity 内的按钮不起作用

android - 为什么我无法在 Android Instant App 中访问相机?

java - eclipse 中的 Proguard 导出错误

android - 如何在 FragmentPagerAdapter 中设置菜单项监听器 (onMenuItemSelected)?

android - fragment 中的 onActivityResult 未称为 childFragment

android - ActionBar 应该在 Fragments 上还是在 Activity 上处理?

java - ListView 未返回精确的滚动位置