#android #kotlin #epoxy
Вопрос:
Я пользуюсь Epoxy library
включенным Android
.
Что мне любопытно, так это то, почему parameter
из lambda expression
них не появляется ошибка, когда тип не совпадает.
Это listener
a lambda expression
, которое принимает an Int type
в качестве параметра.
Но listener(addDetailClicked)
работает нормально.
Разве этого не должно быть listener(Int)
? или listener({ i -> addDetailClicked(i) })
.
На самом деле, я не знаю, почему это работает даже после того, как я напишу код.
Как это возможно?
Модель
@EpoxyModelClass(layout = R.layout.item_routine)
abstract class EpoxyRoutineModel() : EpoxyModelWithHolder<EpoxyRoutineModel.Holder>() {
@EpoxyAttribute
var workout: String = "see"
@EpoxyAttribute
var curPos: Int = 0
@EpoxyAttribute
lateinit var listener: (Int) -> Unit // this
override fun bind(holder: Holder) {
holder.workout.text = workout
holder.add_btn.setOnClickListener {
listener(curPos)
}
}
}
Контроллер
class RoutineItemController(
private val addDetailClicked: (Int) -> Unit)
: EpoxyController() {
private var routineItem : List<RoutineItem>? = emptyList()
override fun buildModels() {
var i:Int =0
routineItem?.forEach {
when(it) {
is RoutineItem.RoutineModel ->
EpoxyRoutineModel_()
.id(i )
.curPos(i )
.workout("d")
.listener(addDetailClicked) // why? listener(Int) or listener({ i -> addDetailClicked(i) })
.addTo(this)
}
}
}
}
Фрагмент
class WriteRoutineFragment : Fragment() {
private var _binding : FragmentWriteRoutineBinding? = null
private val binding get() = _binding!!
private lateinit var epoxyController : RoutineItemController
private val vm : WriteRoutineViewModel by viewModels { WriteRoutineViewModelFactory() }
override fun onCreateView(inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?): View? {
_binding = FragmentWriteRoutineBinding.inflate(inflater, container, false)
epoxyController = RoutineItemController(::addDetail)
binding.rv.adapter = epoxyController.adapter
binding.rv.itemAnimator = null
return binding.root
}
private fun addDetail(pos: Int) {
vm.addDetail2(pos)
}
}
Ответ №1:
Я полагаю, вы упустили тот факт, что EpoxyRoutineModel_
содержит установщики для типов данных, найденных в EpoxyRoutineModel
. Например, EpoxyRoutineModel.curPos
имеет тип Int
, поэтому EpoxyRoutineModel_.curPos()
функция объявлена как:
fun curPos(Int): EpoxyRoutineModel_
(или что-то подобное)
Аналогично, EpoxyRoutineModel.listener
имеет тип (Int) -> Unit
, поэтому EpoxyRoutineModel_.listener()
объявляется как:
fun listener((Int) -> Unit): EpoxyRoutineModel_
Так listener()
же и функция, которая получает другую функцию (которая сама получает Int
). Так что мы можем предоставить addDetailClicked
там.
Комментарии:
1. тогда вы говорите, что это то же самое
Java's user.setcurPos()
,user.setName()
что,user.setNumber()
, и т. Д.?2. У меня нет кода
EpoxyRoutineModel_
, но, похоже, это так. Например,curPos(i )
четко видно , чтоcurPos()
это функция приемаInt
, поэтому она выглядит как своего рода сеттер.3. Итак, причина
listener(addDetailClicked)
возможна в том , чтоlistener()
это не вызов функции, которая принимает anInt
как aparameter
, а просто вызываетsettter function
функциюlistener
для инициализацииlistener property
? Итак, можно ли передатьaddDetailClicked
(Int) -> Unit
соответствующий типlistener property
в качествеargument
?4. Похоже на то, да. Если
curPos()
является задатчиком дляInt
, то аналогичным образомlocation()
должен быть задатчик для(Int) -> Unit
функции. Что на самом деле имеет смысл, потому что вы используетеEpoxyRoutineModel_
для сборкиEpoxyRoutineModel
. Последний содержит свойство для(Int) -> Unit
функции, поэтому конструктор должен предоставить способ его установки.5. Вы должны иметь возможность нажать ctrl
.listener(addDetailClicked)
. Я думаю, вы увидите функцию, объявленную примерно так:fun listener((Int) -> Unit): EpoxyRoutineModel_
. Это подтвердит, что эта функция действительно получает другую функцию.