android - 当 ViewPager 的父 Fragment 隐藏然后显示时,ViewPager 的 Fragment 的 View 丢失

标签 android android-fragments android-viewpager

我的 ViewPager 和我自己的 FragmentStatePagerAdapter 出现了一些奇怪的行为。

我的 View 层次结构是这样的:

-> (1) Fragment root view (RelativeLayout)
 -> (2) ViewPager
  -> (3) ViewPager's current fragment view

当负责 Fragment Root View (1) 的 Fragment 隐藏(在 fragment 事务中使用 .hide())然后显示(使用 .show())时,当前显示在ViewPager (3) 变为 null,尽管 fragment 仍然存在。基本上,我的 ViewPager 变得完全空白/透明。

我发现解决这个问题的唯一方法是调用

int current = myViewPager.getCurrentItem();
myViewPager.setAdapter(myAdapter);
myViewPager.setCurrentItem(current);

在显示父 fragment 之后。这会以某种方式触发 View 被重新创建并出现在屏幕上。不幸的是,这偶尔会导致处理在旧观察者上两次调用 unregisterDataSetObserver() 的寻呼机适配器的异常。

有没有更好的方法来做到这一点?我想我要问的是:

当 ViewPager 的父 fragment 被隐藏时,为什么我的 ViewPager 中的 fragment View 会被破坏?

更新:当应用程序“最小化”然后“恢复”(通过按主操作键然后返回)时也会发生这种情况。

根据请求,这是我的寻呼机适配器类:

public class MyInfoSlidePagerAdapter extends FragmentStatePagerAdapter {

    private ArrayList<MyInfo> infos = new ArrayList<MyInfo>();

    public MyInfoSlidePagerAdapter (FragmentManager fm) {
        super(fm);
    }

    public MyInfoSlidePagerAdapter (FragmentManager fm, MyInfo[] newInfos) {
        super(fm);
        setInfos(newInfos);
    }

    @Override
    public int getItemPosition(Object object) {
        int position = infos.indexOf(((MyInfoDetailsFragment)object).getMyInfo());
        return position > 0 ? position : POSITION_NONE;
    }

    @Override
    public CharSequence getPageTitle(int position) {
        return infos.get(position).getName();
    }

    @Override
    public Fragment getItem(int i) {
        return infos.size() > 0 ? MyInfoDetailsFragment.getNewInstance(infos.get(i)) : null;
    }

    @Override
    public int getCount() {
        return infos.size();
    }

    public Location getMyInfoAtPosition(int i) {
        return infos.get(i);
    }

    public void setInfos(MyInfo[] newInfos) {
        infos = new ArrayList<MyInfo>(Arrays.asList(newInfos));
    }

    public int getPositionOfMyInfo(MyInfo info) {
        return infos.indexOf(info);
    }
}

我已经重命名了一些变量,但除此之外,它正是我所拥有的。

最佳答案

您没有为您的特定问题提供足够的信息,因此我构建了一个示例项目来尝试重现您的问题:该应用程序有一个 Activity ,该 Activity 在相关文件中保存一个 fragment (PagerFragment)布局,在此布局下方,我有一个隐藏和显示在 PagerFragment 上方的按钮。 PagerFragment 有一个 ViewPager 并且分页器适配器中的每个 fragment 只显示一个标签 - 这个 fragment 被命名为 DataFragment。标签列表在父 Activity 中创建并传递给 PagerFragment,然后通过其适配器传递给每个 DataFragment。更改 PagerFragment 可见性没有任何问题,并且每次它再次变得可见时,它都会显示先前显示的标签。

问题的关键: 使用Fragment#getChildFragmentManager()当您创建 viewpager 适配器而不是 getFragmentManager 时!

也许您可以将这个简单的项目与您现有的项目进行比较,并检查差异在哪里。所以这里(自上而下):

PagerActivity(项目中唯一的Activity):

public class PagerActivity extends FragmentActivity {

    private static final String PAGER_TAG = "PagerActivity.PAGER_TAG";

    @Override
    protected void onCreate(Bundle savedInstance) {
        super.onCreate(savedInstance);
        setContentView(R.layout.pager_activity);
        if (savedInstance == null) {
            PagerFragment frag = PagerFragment.newInstance(buildPagerData());
            FragmentManager fm = getSupportFragmentManager();
            fm.beginTransaction().add(R.id.layout_fragments, frag, PAGER_TAG).commit();
        }
        findViewById(R.id.btnFragments).setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                changeFragmentVisibility();
            }
        });
    }

    private List<String> buildPagerData() {
        ArrayList<String> pagerData = new ArrayList<String>();
        pagerData.add("Robert de Niro");
        pagerData.add("John Smith");
        pagerData.add("Valerie Irons");
        pagerData.add("Metallica");
        pagerData.add("Rammstein");
        pagerData.add("Zinedine Zidane");
        pagerData.add("Ronaldo da Lima");
        return pagerData;
    }

    protected void changeFragmentVisibility() {
        Fragment frag = getSupportFragmentManager().findFragmentByTag(PAGER_TAG);
        if (frag == null) {
            Toast.makeText(this, "No PAGER fragment found", Toast.LENGTH_SHORT).show();
            return;
        }
        boolean visible = frag.isVisible();
        Log.d("APSampler", "Pager fragment visibility: " + visible);
        FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
        if (visible) {
            ft.hide(frag);
        } else {
            ft.show(frag);
        }
        ft.commit();
        getSupportFragmentManager().executePendingTransactions();
    }
}

它的布局文件pager_activity.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="4dp" >

    <Button
        android:id="@+id/btnFragments"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:text="Hide/Show fragments" />

    <RelativeLayout
        android:id="@+id/layout_fragments"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_above="@+id/btnFragments"
        android:layout_marginBottom="4dp" >
    </RelativeLayout>

</RelativeLayout>

请注意,我在首次显示 Activity 时添加了 PagerFragment - 以及 PagerFragment 类:

public class PagerFragment extends Fragment {

    private static final String DATA_ARGS_KEY = "PagerFragment.DATA_ARGS_KEY";

    private List<String> data;

    private ViewPager pagerData;

    public static PagerFragment newInstance(List<String> data) {
        PagerFragment pagerFragment = new PagerFragment();
        Bundle args = new Bundle();
        ArrayList<String> argsValue = new ArrayList<String>(data);
        args.putStringArrayList(DATA_ARGS_KEY, argsValue);
        pagerFragment.setArguments(args);
        return pagerFragment;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        data = getArguments().getStringArrayList(DATA_ARGS_KEY);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        return inflater.inflate(R.layout.pager_fragment, container, false);
    }

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        pagerData = (ViewPager) view.findViewById(R.id.pager_data);
        setupPagerData();
    }

    private void setupPagerData() {
        PagerAdapter adapter = new LocalPagerAdapter(getChildFragmentManager(), data);
        pagerData.setAdapter(adapter);
    }

}

它的布局(只有全尺寸的 ViewPager):

<android.support.v4.view.ViewPager xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/pager_data"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

及其适配器:

public class LocalPagerAdapter extends FragmentStatePagerAdapter {
    private List<String> pagerData;

    public LocalPagerAdapter(FragmentManager fm, List<String> pagerData) {
        super(fm);
        this.pagerData = pagerData;
    }

    @Override
    public Fragment getItem(int position) {
        return DataFragment.newInstance(pagerData.get(position));
    }

    @Override
    public int getCount() {
        return pagerData.size();
    }
}

此适配器为每个页面创建一个 DataFragment:

public class DataFragment extends Fragment {
    private static final String DATA_ARG_KEY = "DataFragment.DATA_ARG_KEY";

    private String localData;

    public static DataFragment newInstance(String data) {
        DataFragment df = new DataFragment();
        Bundle args = new Bundle();
        args.putString(DATA_ARG_KEY, data);
        df.setArguments(args);
        return df;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        localData = getArguments().getString(DATA_ARG_KEY);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        return inflater.inflate(R.layout.data_fragment, container, false);
    }

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        view.findViewById(R.id.btn_page_action).setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                Toast.makeText(getActivity(), localData, Toast.LENGTH_SHORT).show();
            }
        });
        ((TextView) view.findViewById(R.id.txt_label)).setText(localData);
    }
}

DataFragment的布局:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="4dp" >

    <Button
        android:id="@+id/btn_page_action"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:text="Interogate" />

    <TextView
        android:id="@+id/txt_label"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:textAppearance="?android:attr/textAppearanceLarge" />

</RelativeLayout>

享受编码!

关于android - 当 ViewPager 的父 Fragment 隐藏然后显示时,ViewPager 的 Fragment 的 View 丢失,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18386254/

相关文章:

android - 使用 ViewPager 开发安全吗?

java - Firebase/GeoQuery - 最大半径 IF 语句

android - 将 Android 中的音频从 48kHz 重采样到 44.1kHz,反之亦然 - 纯 Java 还是 OpenSL ES?

android - 在android中将数据从一个 fragment 传递到另一个 fragment 的最佳方式是什么?

android - RadioGroup 不能在 fragment android 中工作

android - 如何在单击抽屉导航上的项目时打开不同的 Activity ?

android - ViewPager 不会刷新 Fragment

android - 如何从 asp.net web 服务检索 base64 字符串到 android

android - 如何在 Android 中使用 Intent 播放视频?

android - Mortar 和 Flow 库与 ViewPager