Android Kotlin вызывает другой и устаревший конструктор условно - PullRequest
2 голосов
/ 11 марта 2020

У меня есть приложение Android, написанное на Kotlin с классом BaseKeyListener, расширяющим DigitsKeyListener. Моя минимальная версия SDK 21. В настоящее время класс вызывает устаревший конструктор. Однако новый конструктор доступен только с уровня API 26 и выше. Как бы я назвал конструктор условно на основе уровня API?

Я в основном отправил ту же проблему некоторое время go для Android, но решение, похоже, не работает в Kotlin.

В Kotlin мой класс теперь выглядит следующим образом:

// primary constructor 'DigitsKeyListener' shows lint warning about deprecation.
abstract class BaseKeyListener() : DigitsKeyListener() {

}

Если я применяю решение для вопроса Android, я получаю этот код:

abstract class BaseKeyListener : DigitsKeyListener {

    // still results in deprecation warning
    constructor() : super()
}

Было также предоставлено альтернативное решение, если бы мне пришлось сделать конструкторы частными и реализовать шаблон newInstance. Однако я не могу использовать это решение, потому что есть другие классы, которые наследуются от BaseKeyListener, и BaseKeyListener также является абстрактным.

Единственное, о чем я могу думать, это:

abstract class BaseKeyListener : DigitsKeyListener {

   constructor()

    @RequiresApi(Build.VERSION_CODES.O)
   constructor(locale: Locale) : super(locale)
}

Но в результате я должен был бы определить два конструктора для каждого подкласса. И если бы я использовал класс, мне пришлось бы добавлять условие каждый раз, когда используемый нами языковой стандарт одинаков.

Неудачный результат:

open class AmountKeyListener : BaseKeyListener {

    constructor() : super()

    @RequiresApi(Build.VERSION_CODES.O)
    constructor(locale: Locale) : super(locale)
}

// usage of the keyListener
editText.keyListener = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) KeyListenerUtil.AmountKeyListener(
        MY_LOCALE) else KeyListenerUtil.AmountKeyListener()

Идеальным решением должно быть назначение AmountKeyListener в одной строке и BaseKeyListener должны знать, когда использовать нашу пользовательскую локаль 'MY_LOCALE'

editText.keyListener = KeyListenerUtil.AmountKeyListener()

Как решить эту проблему?

1 Ответ

1 голос
/ 11 марта 2020

Решение Java, которое вы в основном связали, просто игнорирует устаревание и использует исключительно устаревший конструктор. Я думаю, что ваше последнее решение является лучшим. Его использование не хуже, чем если бы вы использовали DigitsKeyListener напрямую - вам все равно придется проверять версию SDK.

Одна небольшая проблема, которую я вижу выше, заключается в том, что ваш первый конструктор неявно вызывает пустой супер-конструктор и, таким образом, избегает предупреждения об устаревании через то, что по сути является языковым хаком. Действительно, мне кажется, что это ошибка в инспекторе кода Kotlin. Я думаю, что было бы более уместно явно вызвать супер-конструктор, а также отказаться от этого конструктора в вашем собственном классе. Поэтому я хотел бы, чтобы это выглядело так:

abstract class BaseKeyListener : DigitsKeyListener {

    @Suppress("DEPRECATION")
    @Deprecated("Use the constructor with a locale if on SDK 26+.")
    constructor(): super()

    @RequiresApi(Build.VERSION_CODES.O)
    constructor(locale: Locale) : super(locale)
}

Это функционально не меняет принцип работы, но без устаревшего конструктора становится очень просто случайно использовать устаревшую версию DigitsKeyListener везде.

И на сайте использования, хотя это и болезненно, выглядело бы так, как если бы оно было выше, за исключением того, что вы также ставили бы @Suppress("DEPRECATION") прямо перед этой строкой, чтобы подтвердить предупреждение об устаревании.

...