【问题标题】:ViewPager - first fragment always gets re-created when out of view ( onPause -> onStop -> onAttach->...onResume )ViewPager - 第一个片段总是在视野之外重新创建( onPause -> onStop -> onAttach->...onResume )
【发布时间】:2025-12-14 19:40:05
【问题描述】:

所以我实现了一个带有 FragmentStatePagerAdapterViewPager 并且我有 2 个片段。我使用参数 1 和 2 调用了 setOffscreenPageLimit(),希望不会重新创建片段,但第一个片段总是会重新创建,而第二个片段会被创建。

第一个片段总是经过这些步骤,只要它不在视野范围内(向右滑动到另一个片段,或点击主页按钮等)

  • 暂停
  • onStop
  • 附加上
  • 在创建时
  • onCreateView
  • onStart
  • onResume

由于某种原因,第二个片段只创建一次,如果我滑动到第一个片段,它的行为与预期一样 - 除非我点击主页按钮或电源按钮,否则它不会重新创建。 我想要的行为是两个片段在应用程序的持续时间内创建一次。

我的片段结构如下:

我有一个带有 FrameLayout 的活动。我将我的 SlidingTabFragment 添加到该 FrameLayout。 SlidingTabFragment 本身包含两个片段(2 个选项卡)

FragmentStatePagerAdapter

public class TabsPagerAdapter extends FragmentStatePagerAdapter {

    /** Constructor of the class */
    public TabsPagerAdapter(FragmentManager fm, Context context) {
        super(fm);
        this.mContext = context;
    }

    /** This method will be invoked when a page is requested to create */
    @Override
    public Fragment getItem(int arg0) {
        switch(arg0){
            /** tab1 is selected */
            case 0:
                Fragment1 frag1 = new Fragment1();
                return frag1;
            /** tab2 is selected */
            case 1:
                Fragment2 frag2 = new Fragment2();
                return frag2;
        }
        return null;
    }

    @Override
    public CharSequence getPageTitle(int position) {
        return Settings.TAB_TITLES[position];
    }

    /** Returns the number of pages */
    @Override
    public int getCount() {
        return Settings.TAB_TITLES.length;
    }
}

父片段:

public class SlidingTabFragment extends Fragment {

    ViewPager pager = null;
    TabsPagerAdapter adapter = null;
    SlidingTabLayout tabs = null;

    public static SlidingTabFragment newInstance() {
        SlidingTabFragment fragment = new SlidingTabFragment();
        return fragment;
    }

    public SlidingTabFragment() {
        // Required empty public constructor
    }

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

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
    }

    @Override
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        adapter =  new TabsPagerAdapter(getChildFragmentManager(), getActivity());

        pager = (ViewPager) view.findViewById(R.id.pager);
        pager.setAdapter(adapter);
        pager.setOffscreenPageLimit(2);

        // Assigning the Sliding Tab Layout View
        tabs = (SlidingTabLayout) view.findViewById(R.id.sliding_layout);
        tabs.setCustomTabView(R.layout.custom_tab_view, 0);
        tabs.setDistributeEvenly(true);

        // Setting indicator color to white
        tabs.setCustomTabColorizer(new SlidingTabLayout.TabColorizer() {
            @Override
            public int getIndicatorColor(int position) {
                return getResources().getColor(R.color.White);
            }
        });

        tabs.setViewPager(pager);
    }

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

R.layout.fragment_sliding_tab

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/activity_series_details"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    <com.myapp.views.SlidingTabLayout
        android:id="@+id/sliding_layout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:elevation="2dp"
        android:background="@color/tab_bar_background_color"
        />
    <android.support.v4.view.ViewPager
        android:id="@+id/pager"
        android:layout_height="0dp"
        android:layout_width="match_parent"
        android:layout_weight="1" />
</LinearLayout>

【问题讨论】:

  • 如果您将屏幕外限制保留为默认值并且不调用setoffscreenPagelimit会发生什么?
  • 你是在调用 newInstance() 来创建父片段
  • @war_Hero 是的,我愿意。在我的主要活动中,我调用:transaction.replace(R.id.fragment_container, SlidingTabFragment.newInstance());大卫,我以前有过,这就是促使我使用 setOffScreenPageLimit() 的原因
  • 这可能会发生,只需在替换代码中传递新的 ParentFragment 一次。
  • @war_Hero,你的意思是这样吗:transaction.replace(R.id.fragment_container, new SlidingTabFragment()); ?我刚才确实尝试过这个,我得到了同样的行为。

标签: android android-fragments android-viewpager adapter


【解决方案1】:

将此添加到您的片段中:

@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
    super.setUserVisibleHint(isVisibleToUser);
    if (isVisibleToUser) {
        // load data here
    }else{
       // fragment is no longer visible
    }
}

【讨论】:

  • 这对我的问题有什么帮助?
  • 您不希望页面被多次重新创建。这让您仅在用户可见时才加载数据
  • 我其实不想要那个。我希望在应用程序执行期间创建一次片段。一旦创建,他们就会自行更新。我不想在片段每次进入视图时加载数据。
  • 然后将它们设置为static。试着告诉我它是否有效
  • 您能否通过将它们设置为静态来明确说明您的意思?
最近更新 更多