androidandroid-studiokotlincompanion-object

Kotlin - Accessing Objects of class if the name of Object is stored in a String


I have a class which is having multiple companion objects which are lists of strings. In another class (Activity) I am having a string which can have name of any of the companion object. Is there a way of accessing other class's companion object without If/Else statements.

DataLists

class ProjectDataLists {
    companion object {
        var Countries: List<String> = listOf(
          "USA",
          "Canada",
          "Australia",
          "UK"
        )

        var Cars: List<String> = listOf(
          "Toyota",
          "Suzuki",
          "Honda",
          "Ford"
        )
    }
}

Activity Class

var IntentVariable: String = "Countries" //This is an Intent variable (extra) from another activity
var DataToBeFetched : List<String>? = null
if (IntentVariable == "Countries")
{
  DataToBeFetched = ProjectDataLists.Countries
}
else if (IntentVariable == "Cars")
{
  DataToBeFetched = ProjectDataLists.Cars
}

I want last part of Activity class to be done without if/else


Solution

  • You could use reflection:

    import kotlin.reflect.full.companionObject
    import kotlin.reflect.full.memberProperties
    
    class ProjectDataLists {
      companion object {
        var Countries: List<String> = listOf("USA", "Canada", "Australia", "UK")
        var Cars: List<String> = listOf("Toyota", "Suzuki", "Honda", "Ford")
      }
    }
    
    var intentVariable = "Countries"
    
    val dataToBeFetched = (ProjectDataLists::class
      .companionObject!!
      .memberProperties
      .first { it.name == intentVariable }   // Will crash with NoSuchElementException if intentVariable is not existing
      .call(ProjectDataLists) as List<*>)
      .filterIsInstance<String>()
    
    println(dataToBeFetched)   // Output: [USA, Canada, Australia, UK]
    

    But if you have only a few lists in your companion object, I would recommend to not use reflection. Note that you can simplify your if statement by using when:

    val dataToBeFetched = when (intentVariable) {
      "Countries" -> ProjectDataLists.Countries
      "Cars"      -> ProjectDataLists.Cars
      // and more here ...
    }
    

    This is very readable and in comparison to reflection very explicit and safe.