Android:如何在ViewPager中容纳1000个动态Fragment?
Ah, I get it—you tried using ViewPager with 1000 Fragments for your questions, and it crashed or wouldn't load. That makes total sense because each Fragment is a separate object, and 1000 of them will gobble up way too much memory—the system will either kill your app or refuse to instantiate that many. Let's go through the best solutions to handle this scale efficiently.
Why Your Original Approach Failed
The default ViewPager (with FragmentPagerAdapter) keeps every Fragment you create in memory permanently. Even if you crank up offscreenPageLimit, you're still asking the system to hold hundreds of Fragment instances at once—this is a non-starter for 1000 items.
Best Solution: ViewPager2 + View Reuse (No Fragments Needed)
ViewPager2 is built on RecyclerView, which means it supports view recycling out of the box. Instead of creating a Fragment per question, we'll reuse a single layout template for all questions. This is way more memory-efficient and fast.
Step 1: Define Your Question Data Class
First, create a data class to hold each question's details:
data class Question( val id: Int, val title: String, val options: List<String>, val correctAnswer: Int, var userAnswer: Int? = null // Track user's selection )
Step 2: Create a Reusable Question Item Layout
Make an item_question.xml layout for your question + 4 options (use a RadioGroup for single-choice):
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:padding="16dp"> <TextView android:id="@+id/tv_question_title" android:layout_width="match_parent" android:layout_height="wrap_content" android:textSize="18sp" android:marginBottom="16dp"/> <RadioGroup android:id="@+id/rg_options" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"/> </LinearLayout>
Step 3: Build a RecyclerView Adapter for ViewPager2
This adapter will inflate the item layout once, then reuse it for every question:
class QuestionAdapter(private val questions: List<Question>) : RecyclerView.Adapter<QuestionAdapter.ViewHolder>() { inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { val tvTitle: TextView = itemView.findViewById(R.id.tv_question_title) val rgOptions: RadioGroup = itemView.findViewById(R.id.rg_options) } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { val view = LayoutInflater.from(parent.context) .inflate(R.layout.item_question, parent, false) return ViewHolder(view) } override fun onBindViewHolder(holder: ViewHolder, position: Int) { val question = questions[position] // Bind question title holder.tvTitle.text = question.title // Clear existing options (critical for recycling) holder.rgOptions.removeAllViews() // Add 4 options to the RadioGroup question.options.forEachIndexed { index, optionText -> val radioButton = RadioButton(holder.rgOptions.context).apply { text = optionText id = index isChecked = (index == question.userAnswer) // Restore user's selection } holder.rgOptions.addView(radioButton) } // Save user's selection when they choose an option holder.rgOptions.setOnCheckedChangeListener { _, checkedId -> question.userAnswer = checkedId } } override fun getItemCount() = questions.size }
Step 4: Set Up ViewPager2 in Your Activity
Initialize ViewPager2 and attach the adapter:
class QuestionActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_question) val viewPager2 = findViewById<ViewPager2>(R.id.view_pager2) // Generate 1000 sample questions (replace with your real data) val questions = List(1000) { index -> Question( id = index + 1, title = "Question ${index + 1}: Which of the following is correct?", options = listOf("Option A", "Option B", "Option C", "Option D"), correctAnswer = (0..3).random() ) } viewPager2.adapter = QuestionAdapter(questions) } }
Alternative: If You Must Use Fragments
If you have a specific need to use Fragments (e.g., complex per-question logic), use FragmentStateAdapter with ViewPager2. This adapter destroys Fragments that are off-screen and only saves their state, which is much more memory-friendly than FragmentPagerAdapter.
Example FragmentStateAdapter
class QuestionFragmentAdapter(activity: FragmentActivity, private val questions: List<Question>) : FragmentStateAdapter(activity) { override fun getItemCount() = questions.size override fun createFragment(position: Int): Fragment { return QuestionFragment.newInstance(questions[position]) } } // Your QuestionFragment class class QuestionFragment : Fragment() { companion object { private const val ARG_QUESTION = "question" fun newInstance(question: Question): QuestionFragment { val args = Bundle().apply { putParcelable(ARG_QUESTION, question) } return QuestionFragment().apply { arguments = args } } } override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { val view = inflater.inflate(R.layout.fragment_question, container, false) val question = arguments?.getParcelable<Question>(ARG_QUESTION) ?: return view // Bind data to your Fragment's views here return view } }
Important Note: State Preservation
Whichever approach you choose, make sure to save the user's answers when the app is rotated or backgrounded. Use a ViewModel (with SavedStateHandle if needed) to persist the userAnswer values across configuration changes.
内容的提问来源于stack exchange,提问作者raguM.tech.

