You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

竖屏切换横屏时ViewPager中Fragment无法移除问题求助

Fixing Fragment Leaks When Switching Between Portrait and Landscape

Hey, I’ve dealt with this exact problem before—orientation changes can be tricky with Fragments because Android automatically saves and restores Fragment instances for you, which leads to those leftover ViewPager Fragments sticking around even after you switch layouts. Let’s walk through the solution step by step.

Why Your Current Code Isn’t Working

When you rotate the screen, Android destroys and recreates your Activity. The FragmentManager automatically keeps track of all Fragments you added earlier (including the ones in your ViewPager). Even though your landscape layout doesn’t have a ViewPager, those old Fragments are still in the FragmentManager, in a "detached" state. When the Activity recreates, the FragmentManager tries to restore their views, which is why onCreateView() is still being called. Your replace calls only affect the new landscape containers—they don’t touch the old ViewPager Fragments.

Step 1: Clean Up Old Fragments First

Before setting up your new layout (whether portrait or landscape), you need to explicitly remove any existing Fragments that might conflict. Add this code right after initializing your ViewModel:

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    viewModel = ViewModelProviders.of(this).get(MainViewModel.class);

    // Clean up existing Fragments to avoid duplicates/leaks
    FragmentManager fragmentManager = getSupportFragmentManager();
    FragmentTransaction cleanupTransaction = fragmentManager.beginTransaction();

    // Remove Fragments tagged for landscape
    Fragment oldCurrent = fragmentManager.findFragmentByTag("current");
    Fragment oldForecast = fragmentManager.findFragmentByTag("forecast");
    if (oldCurrent != null) cleanupTransaction.remove(oldCurrent);
    if (oldForecast != null) cleanupTransaction.remove(oldForecast);

    // Remove ViewPager Fragments (their tags follow the pattern: "android:switcher:[viewPagerId]:[position]")
    Fragment viewPagerCurrent = fragmentManager.findFragmentByTag("android:switcher:" + R.id.pager + ":0");
    Fragment viewPagerForecast = fragmentManager.findFragmentByTag("android:switcher:" + R.id.pager + ":1");
    if (viewPagerCurrent != null) cleanupTransaction.remove(viewPagerCurrent);
    if (viewPagerForecast != null) cleanupTransaction.remove(viewPagerForecast);

    // Use commitNow() to execute immediately (avoids async conflicts)
    cleanupTransaction.commitNow();

    // Rest of your orientation logic...
    int orientation = getResources().getConfiguration().orientation;
    if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
        FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
        fragmentTransaction.replace(R.id.weather_layout, new CurrentWeatherFragment(), "current");
        fragmentTransaction.replace(R.id.forecast_layout, new ForecastFragment(), "forecast");
        fragmentTransaction.commit();
    } else {
        ViewPager viewPager = findViewById(R.id.pager);
        WeatherPageAdapter weatherPageAdapter = new WeatherPageAdapter(getSupportFragmentManager());
        viewPager.setAdapter(weatherPageAdapter);
        viewPager.addOnPageChangeListener(new WeatherPageChangedListener());
        viewPager.setCurrentItem(viewModel.getViewPagerPosition(), false);
    }
}

FragmentPagerAdapter caches Fragments permanently, which is part of why they stick around even after the ViewPager is gone. If you want Fragments to be destroyed when they’re no longer needed (while still saving their state), switch to FragmentStatePagerAdapter:

public class WeatherPageAdapter extends FragmentStatePagerAdapter {
    private static final int pageNumber = 2;

    public WeatherPageAdapter(FragmentManager fragmentManager) {
        // Use BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT to only load the visible Fragment
        super(fragmentManager, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT);
    }

    @Override
    public int getCount() {
        return pageNumber;
    }

    @Override
    public Fragment getItem(int i) {
        if (i == 0) {
            return new CurrentWeatherFragment();
        } else {
            return new ForecastFragment();
        }
    }
}

Step 3: Save Fragment State (Avoid Data Loss)

Make sure your Fragments save their state so you don’t lose data during rotation. Add this to each Fragment:

@Override
public void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    // Save your data here (e.g., weather objects, user input)
    outState.putParcelable("weather_data", yourWeatherDataObject);
}

Then restore it in onCreateView:

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.your_fragment_layout, container, false);
    
    if (savedInstanceState != null) {
        // Restore your data
        yourWeatherDataObject = savedInstanceState.getParcelable("weather_data");
        // Update your UI with the restored data
    }

    return view;
}

These changes should stop the old ViewPager Fragments from being recreated when you switch to landscape, and ensure your new landscape Fragments work as expected.

内容的提问来源于stack exchange,提问作者Кирилл Волков

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 08:57:59