I have a viewpager2 adapter
class SectionPager2(fragment: Fragment): FragmentStateAdapter(fragment) {
private val fragmentList = mutableListOf<Fragment>()
override fun getItemCount() = fragmentList.size
override fun createFragment(position: Int) = fragmentList[position]
fun addFragment(position: Int, fragment: Fragment) {
fragmentList.add(position, fragment)
}
}
I use it along with a Tablayout like this
val sectionPagerAdapter = SectionPager2(this)
for (item in gradeSectionMajorOrdered) {
var title = ""
fragment = HomeDetailTempFragment.newInstance(thisFragment, item.majors!!, item.gradeSectionId)
gradeSectionIds.add(item.gradeSectionId)
for (i in viewModel.gradeSections.value?.result!!) {
if (i.id == item.gradeSectionId) title = i.name
}
majorItems.add(item.majors)
gradeSectionId = item.gradeSectionId
sectionPagerAdapter.addFragment(gradeSectionMajorOrdered.indexOf(item), fragment)
fragmentTitleList.add(gradeSectionMajorOrdered.indexOf(item), title)
}
Here I get HomeDetailTempFragment data from a server, the problem is that when I use HomeDetailTempFragment.newInstance(thisFragment, item.majors!!, item.gradeSectionId) the code for example generates 3 the same data HomeDetailTempFragment view in viewpager but if I change this and remove companion object newInstance from HomeDetailTempFragment it works correctly and we all know what's gonna happen sometimes on some devices we get unable to intantiate fatal error.
This class does not work correctly:
@SuppressLint("ValidFragment")
class HomeDetailTempFragment : BaseFragment(), MajorRecyclerViewAdapter.IMajorRV {
companion object {
private lateinit var listener: OnClick
private lateinit var items: List<MajorGrades>
private var gradeSectionId = 0
fun newInstance(
listener: HomeDetailFragment,
items: List<MajorGrades>,
gradeSectionId: Int,
) = HomeDetailTempFragment().also {
this.listener = listener
this.gradeSectionId = gradeSectionId
this.items = items
}
}
private lateinit var mContext : Context
private lateinit var binding: FragmentHomeDetailTempBinding
override fun onCreateView(inflater : LayoutInflater,
container : ViewGroup?,
savedInstanceState : Bundle?) : View {
binding = FragmentHomeDetailTempBinding.inflate(layoutInflater)
return binding.root
}
override fun onViewCreated(view : View, savedInstanceState : Bundle?) {
super.onViewCreated(view, savedInstanceState)
mContext = requireContext()
binding.rvGradeMajor.adapter = MajorRecyclerViewAdapter(context = mContext,
majors = items,
gradeSectionId = gradeSectionId,
listener = this)
}
override fun onGradeMajorClick(majorItem : MajorGrades, gradeItem : MajorGrades) {
listener.onGradeMajorClick(gradeSectionId, majorItem, gradeItem)
}
}
If I change the class this way it works as expected
@SuppressLint("ValidFragment")
class HomeDetailTempFragment(private val listener : OnClick,
private val items : List<MajorGrades>,
private val gradeSectionId : Int)
: BaseFragment(), MajorRecyclerViewAdapter.IMajorRV {
private lateinit var mContext : Context
private lateinit var binding: FragmentHomeDetailTempBinding
override fun onCreateView(inflater : LayoutInflater,
container : ViewGroup?,
savedInstanceState : Bundle?) : View {
binding = FragmentHomeDetailTempBinding.inflate(layoutInflater)
return binding.root
}
override fun onViewCreated(view : View, savedInstanceState : Bundle?) {
super.onViewCreated(view, savedInstanceState)
mContext = requireContext()
binding.rvGradeMajor.adapter = MajorRecyclerViewAdapter(context = mContext,
majors = items,
gradeSectionId = gradeSectionId,
listener = this)
}
override fun onGradeMajorClick(majorItem : MajorGrades, gradeItem : MajorGrades) {
listener.onGradeMajorClick(gradeSectionId, majorItem, gradeItem)
}
}
CodePudding user response:
Both your approaches to creating fragments are wrong.
In the first case you write data to companion object
of HomeDetailTempFragment
. This is same as writing to a static
variable in Java. So you get only the data you wrote last - for the last fragment.
The second case would fail as soon as Android system decided to recreate your fragment, for example on screen rotation, because it would call empty constructor. But I assume it just fails to compile.
The correct way is to use setArguments
in newInstance
and getArguments
in onViewCreated
(or onCreateView
). See this question for more info, including Kotlin implementation.
However I suspect you won't be able to put List<MajorGrades>
into the Bundle
. Also Bundle
s have limited size. Instead I'd suggest using a shared ViewModel for the data and passing only fragment's position via the arguments.