Как сохранить и восстановить лямбды в Android? - PullRequest
0 голосов
/ 27 декабря 2018

Когда я выполняю восстановление состояния в Android, как я могу сохранить и восстановить лямбду?

Я пытался сохранить его как Serializable и Parcelable, но он выдает ошибку компиляции.

Есть ли какие-либоспособ сохранить и восстановить их, или я должен искать другие подходы?

Ответы [ 2 ]

0 голосов
/ 27 декабря 2018

Должен ли я искать другие подходы?

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

Вместо сохранения функции сохранитепараметры (т.е. переменные в scope ), которые необходимо сохранить, и вызовите функцию, как обычно.

Пример

Вместо выполнения

val name = "John Smith"
val sayHello = { "Hi there, $name" }

startActivity(Intent().apply { putExtra("GREETER", sayHello as Serializable) })

Создать функцию, которую вы можете использовать в другом месте

fun sayHello(name: String) = { "Hi there, $name" }

И вызыватьс восстановленным параметром name позже

0 голосов
/ 27 декабря 2018

Kotlin lambdas реализует Serializable, поэтому их нельзя сохранить как:

override fun onSaveInstanceState(outState: Bundle) {
    outState.putSerializable("YOUR_TAG", myLambda as Serializable)
    super.onSaveInstanceState(outState)
}

Аналогично, чтобы восстановить их:

override fun onCreate(savedInstanceState: Bundle?) {
    myLambda = savedInstanceState?.getSerializable("YOUR_TAG") as (MyObject) -> Void
    super.onCreate(savedInstanceState)
}

(Это, очевидно, можно сделать влюбое из событий жизненного цикла, которые предлагают вам savedInstanceState, как это было только в качестве примера)

Некоторые примечания:

  • При сохранении их необходимо привести в исполнение, иначе компиляторжалуется (по какой-то причине).
  • import java.io.Serializable требуется.
  • Метод, при котором вы возвращаете его к вашему лямбда-типу, выдаст предупреждение Unchecked cast: Serializable? to YourLambdaType.Это приведение является безопасным (при условии, что вы правильно выводите обнуляемость!), Поэтому вы можете безопасно подавить это предупреждение, используя @Suppress("UNCHECKED_CAST")
  • MyObject, должно быть Serializable или Parcelable, иначе оно вылетает во время выполнения.

Теперь есть деталь, которая нигде не сообщается и падает во время выполнения без полезных журналов аварий.Внутренняя реализация вашей лямбды (т.е. то, что находится внутри { }, когда вы ее назначаете) не должна иметь ссылок на объекты, которые будут освобождены в более поздний момент.Классическим примером будет:

// In your MyActivity.kt…
myLambda = { handleLambdaCallback() } 
…

private fun handleLambdaCallback() {
    …
}

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

Одним из решений этой проблемы является отправка ссылки в лямбду.Пример:

// In your MyActivity.kt…
myLambda = { fragment -> (fragment.activity as MyActivity).handleLambdaCallback() }
…

private fun handleLambdaCallback() {
    …
}

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

Не стесняйтесь предлагать улучшения и альтернативные решения!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...