Получить класс по строковому имени в Android, чтобы избежать повторения - PullRequest
0 голосов
/ 25 апреля 2020

Итак, в моем коде я получаю список строк, которые соответствуют жанрам mov ie в перечислении. Затем я получаю файл метаданных и просматриваю каждый из этих жанров, чтобы узнать, является ли дата, когда сервер обновил этот жанр, новее, чем дата, когда я извлек эти фильмы и сохранил их в базе данных. Короче говоря, в файле метаданных есть классы для каждого из жанров, и я делаю ТОНА повторения, просто потому, что не могу придумать, как программно сообщить своему приложению, что, например, если вы оцениваете жанр ACTION, вам следует взглянуть на переменную-член metadata.action. Вот мой код, я его урезал, но есть пара десятков жанров.

TwMetadata

data class TwMetadata (

        @SerializedName("action") var action : Action,
        @SerializedName("adventure") var adventure : Adventure,
        @SerializedName("animation") var animation : Animation,
        @SerializedName("comedy") var comedy : Comedy,

)

В следующем коде я взял список строк, которые я извлек с сервера, преобразовал их в перечисления жанров, и я проверяю дату последнего обновления в файле метаданных sharedpreferences (spObj), по сравнению с датой последнего обновления в недавно извлеченном файле метаданных (metadata.value). Если появляются новые данные, я изменяю дату в файле метаданных sharedpreferences, который я фиксирую в конце этого завершаемого файла. Затем я отправляю его функции, которая извлекает данные из базы данных или из Интернета, в зависимости от значения логического значения, которое я отправляю. В идеале я мог бы избавиться от всего этого блока «когда» и просто запустить одну функцию для каждого жанра, но для этого им нужно было бы знать, какому классу они соответствуют в файле метаданных.

  private fun checkGenreDate(genreList: MutableList<GENRE>) : Completable {
    return Completable.create { emitter ->

      var getNew = json.isNullOrEmpty()

      genreList.forEach {
        when (it) {
          GENRE.NULL -> {
          }
          GENRE.ACTION -> {
            if (spObj.action.updated < metadata.value!!.action.updated) {
              getNew = true
              spObj.action = metadata.value!!.action
            }
            loadFromTwApi(it, getNew)
          }
          GENRE.ADVENTURE -> {
            if (spObj.adventure.updated < metadata.value!!.adventure.updated) {
              getNew = true
              spObj.adventure = metadata.value!!.adventure
            }
            loadFromTwApi(it, getNew)
          }
          GENRE.ANIMATION -> {
            if (spObj.animation.updated < metadata.value!!.animation.updated) {
              getNew = true
              spObj.animation = metadata.value!!.animation

            }
            loadFromTwApi(it, getNew)
          }
          GENRE.COMEDY -> {
            if (spObj.comedy.updated < metadata.value!!.comedy.updated) {
              getNew = true
              spObj.comedy = metadata.value!!.comedy
            }
            loadFromTwApi(it, getNew)
          }
          GENRE.RANDOM -> {
          }
          GENRE.THEATER -> {
            loadTheaterData()
          }
        }
      }
      emitter.onComplete()
    }
  }

мой перечислимый класс

enum class GENRE {
  NULL,
  ACTION,
  ADVENTURE,
  ANIMATION,
  COMEDY,
  RANDOM,
  THEATER;

  companion object {
    fun getGenreByName(name: String) = try {
      (name.toUpperCase(Locale.getDefault()))
    } catch (e: IllegalArgumentException) {
      null
    }
  }

1 Ответ

0 голосов
/ 25 апреля 2020

Я предлагаю обобщенный c запечатанный класс с абстрактными методами получения и установки метаданных, а также метод поиска stati c, включенный в запечатанный класс. В значительной степени Kotlin magi c для превращения перечислений в иерархию классов, чтобы вы могли совместно использовать и применять функциональность среди них.

Так что для действий и приключений, вот функция updateAllGenres, которая обновит все метаданные.

fun updateAllGenres( spObj: TwMetadata, metadata: MetadataFile ) {
    Genre.forEach {
        it.maybeUpdateSharedMetadata( spObj, metadata )
    }
}

sealed class Genre < T : GenreMetadata > {
    companion object {
        fun forEach( callback: ( Genre < * > ) -> Unit ) {
            Genre::class.sealedSubclasses.forEach {
                callback( it.objectInstance as Genre < * > )
            }
        }
    }

    fun maybeUpdateSharedMetadata( spObj: TwMetadata, metadata: MetadataFile ): Boolean {
        val genreMetadataInFile = getGenreMetadata( metadata.value!! )
        return getGenreMetadata( spObj ).updated < genreMetadataInFile.updated
            .also { setGenreMetadataInDictionary( spObj, genreMetadataInFile )
        }
    }

    protected abstract fun getGenreMetadata( metadata: TwMetadata ): T
    protected abstract fun setGenreMetadataInDictionary( metadata: TwMetadata, genreMetadata: T )
}

object ActionGenre : Genre < Action >() {
    override fun getGenreMetadata( metadata: TwMetadata ): Action {
        return metadata.action
    }

    override fun setGenreMetadataInDictionary( metadata: TwMetadata, genreMetadata: Action ) {
        metadata.action = genreMetadata
    }
}

object AdventureGenre : Genre < Adventure >() {
    override fun getGenreMetadata( metadata: TwMetadata ): Adventure {
        return metadata.adventure
    }

    override fun setGenreMetadataInDictionary( metadata: TwMetadata, genreMetadata: Adventure ) {
        metadata.adventure = genreMetadata
    }
}

Требуется еще пара настроек, чтобы точно выполнить вашу функцию, но я уверен, что вы поняли идею. Кроме того, вы можете захотеть на go продвинуться дальше и взглянуть на объединение запечатанных подклассов и классов Action, Adventure et c, которые содержат метаданные, но это немного больше работы.

Для справки приведенные выше интерфейсы:

interface Action : GenreMetadata {}
interface Adventure : GenreMetadata {}

interface GenreMetadata {
    val updated: Long
}

interface TwMetadata {
    var action: Action
    var adventure: Adventure
}

interface MetadataFile {
    val value: TwMetadata?
}
...