2

This question is basically a copy of "Java list of uninstantiated classes" but for Kotlin.

My use case is that I have a FragmentStatePagerAdapter and I would like to pass it an ArrayList of uninstantiated Fragments. I have an abstract base class TutorialSlideFragment that defines a basic class for some slides in a tutorial. Then, I have 20+ Fragments that extend TutorialSlideFragment to add some more functionality if needed. I would like to pass an ArrayList of uninstantiated TutorialSlideFragment so that the adapter can instantiate them in the right class when needed.

Currently, I have the following:

ArrayList<Class<TutorialSlideFragment>> = arrayListOf( TutorialSlideFragment::class.java )

This works, but let's not forget that TutorialSlideFragment is abstract, so this is not what I want to do. I created a WelcomeSlideFragment that extends TutorialSlideFragment. If I do the following:

var tutorialSlides: ArrayList<Class<TutorialSlideFragment>> = arrayListOf(
        WelcomeFragment::class.java
)

I get the following error:

Type inference failed. Expected type mismatch:
required:kotlin.collections.ArrayList<Class<TutorialSlideFragment>>
found:   kotlin.collections.ArrayList<Class<WelcomeFragment>>

How can I have an ArrayList on uninstantiated classes that extend a base class?

ThomasFromUganda
  • 380
  • 3
  • 17
  • Try `var tutorialSlides: ArrayList>`. Or, take a more Kotlin-y approach, and have your list be of lambda expressions that can create the desired fragment, instead of having your adapter rely on reflection. – CommonsWare Feb 29 '20 at 17:45
  • @CommonsWare It would need to be covariant, not contravariant in this case. – Tenfour04 Feb 29 '20 at 17:57
  • @Tenfour04: Thanks! Those always make my head hurt. – CommonsWare Feb 29 '20 at 18:01

1 Answers1

3

Specify your type as covariant (out) so subclass types can be included:

var tutorialSlides: ArrayList<Class<out TutorialSlideFragment>> = arrayListOf(
        WelcomeFragment::class.java
)

Or to make it easier to instantiate them later, you can specify a list of constructors:

val tutorialSlides: ArrayList<() -> TutorialSlideFragment> = arrayListOf(
        ::WelcomeFragment
)

and call the constructors like any other function:

val newFragment = tutorialSlides[0]()
Tenfour04
  • 83,111
  • 11
  • 94
  • 154