Можем ли мы передать аргументы фрагментам более красиво? - PullRequest
0 голосов
/ 31 января 2019

Для каждого класса Fragment, который я делаю, я добавляю что-то вроде этого:

companion object {
    private const val PARAMETER_1 = "parameter1"
    private const val PARAMETER_2 = "parameter2"

    fun newInstance(parameter1: String, parameter2: Int) = MyDialog().apply {
        arguments = bundleOf(
            PARAMETER_1 to parameter1,
            PARAMETER_2 to parameter2)
    }
}

И затем добавляю:

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    val args = arguments ?: return

    property1 = args[PARAMETER_1]
    property2 = args[PARAMETER_2]
}

Это не ужасно.Но это образец, от которого было бы здорово избавиться.

Вот моя попытка на данный момент:

abstract class BaseFragment : Fragment() {
  abstract val constructorArguments: List<KMutableProperty<*>>

  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    val args = arguments ?: return

    constructorArguments.forEach {
        val key = keyPrefix + it.name
        val argument = args.get(key)
        val clazz = it.javaClass
        val typedArgument = clazz.cast(argument)
        it.setter.call(typedArgument)
    }
  }

  companion object {
    const val keyPrefix = "ARGUMENT_"

    fun newInstance(fragment: BaseFragment, vararg parameters: Any): BaseFragment {
        val constructorArguments = fragment.constructorArguments
        val parameterMap = mutableListOf<Pair<String, Any?>>()
        constructorArguments.forEachIndexed { index, kMutableProperty ->
            val key = keyPrefix + kMutableProperty.name
            val parameter = parameters[index]
            parameterMap.add(Pair(key, parameter))
        }
        val args = bundleOf(*parameterMap.toTypedArray())
        fragment.arguments = args
        return fragment
    }
  }
}

И затем, в фактическом фрагменте я могу просто иметь:

class MyFragment : BaseFragment() {

  lateinit var myProperty: String

  override val constructorArguments = listOf<KMutableProperty<*>>(
    ::myProperty
  )

  companion object {
    fun newInstance(argument: String) = BaseFragment.newInstance(MyFragment(), argument)
  }
}

Этот подход далек от совершенства, особенно:

val parameter = parameters[index]

Кто-нибудь знает лучший способ сделать это?У вас есть предложения по улучшению моего подхода?Или вся эта идея обречена на провал, и я потратил впустую утро?

1 Ответ

0 голосов
/ 11 июня 2019

«Ответ» на этот вопрос заключается в использовании библиотеки навигации Android Jetpack.Он предоставляет SafeArgs, который значительно упрощает передачу аргументов в фрагменты.См .:

https://developer.android.com/guide/navigation/navigation-pass-data#Safe-args

...