ViewPager实现底部导航崩溃:Fragment already added异常求助
Hey there, let's break down why you're hitting this IllegalStateException: Fragment already added error and how to fix it.
Root Cause
The main issue here is that you're duplicating Fragment caching alongside FragmentPagerAdapter's built-in mechanism. The adapter already handles retaining and reusing Fragments internally, but your custom instantiatedFragments SparseArray is interfering with this process—especially during configuration changes (like screen rotation) or when the adapter is reinitialized. When the system tries to restore cached Fragments, your code might be trying to add an already-existing Fragment instance again.
Step-by-Step Fixes
1. Remove Your Custom Fragment Cache
First, get rid of the instantiatedFragments SparseArray and all related code in instantiateItem and destroyItem. You don't need to manually track Fragments because FragmentPagerAdapter does this for you. Here's the cleaned-up adapter:
class HomePageAdapter(fragmentManager: FragmentManager) : FragmentPagerAdapter(fragmentManager, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) { companion object { const val FRAGMENT_INDEX_REPO = 0 const val FRAGMENT_INDEX_DEV = 1 const val NUM_OF_ITEMS = 2 const val FRAGMENT_DEV_TITLE = "Developers" const val FRAGMENT_REPO_TITLE = "Repositories" } override fun getItem(position: Int): Fragment { return if (position == FRAGMENT_INDEX_REPO) { RepositoriesFragment.newInstance() } else { DevelopersFragment.newInstance() } } override fun getPageTitle(position: Int): CharSequence? { return if (position == FRAGMENT_INDEX_REPO) { FRAGMENT_REPO_TITLE } else { FRAGMENT_DEV_TITLE } } override fun getCount(): Int { return NUM_OF_ITEMS } }
2. Ensure Your Adapter Is Initialized Only Once
Make sure you're not creating a new instance of HomePageAdapter every time onCreate is called (e.g., during screen rotation). Store the adapter as a member variable in your Activity/Fragment:
class MainActivity : AppCompatActivity() { private lateinit var viewPager: ViewPager private lateinit var homePageAdapter: HomePageAdapter override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) viewPager = findViewById(R.id.viewPager) // Initialize adapter only once, or reuse if savedInstanceState exists homePageAdapter = HomePageAdapter(supportFragmentManager) viewPager.adapter = homePageAdapter } }
3. Verify Fragment newInstance Implementation (If Needed)
Double-check that your newInstance methods in RepositoriesFragment and DevelopersFragment are correctly creating new instances (not returning a singleton). A standard implementation looks like this:
class RepositoriesFragment : Fragment() { companion object { fun newInstance(): RepositoriesFragment { return RepositoriesFragment() } } // Rest of your fragment code... }
Why This Works
FragmentPagerAdapter keeps references to Fragments it has created, and when the system restores the FragmentManager state (after configuration changes), it reuses those existing instances. Your custom cache was trying to track Fragments independently, leading to conflicts where the adapter tried to add a Fragment that was already present in the FragmentManager.
Bonus: Consider Migrating to ViewPager2
If you're starting a new feature or have the bandwidth, Google recommends using ViewPager2 instead of the old ViewPager. ViewPager2 uses FragmentStateAdapter, which has better support for modern Fragment behaviors and avoids many of these caching-related issues. The migration is straightforward, and you'll get additional benefits like vertical scrolling and RTL support.
内容的提问来源于stack exchange,提问作者pandey_shubham

