Home > database >  In the code, the type of the lambda is mismatched, how does it work?
In the code, the type of the lambda is mismatched, how does it work?

Time:10-20

I'm using the Epoxy library on Android.

What I'm curious about is why the parameter of the lambda expression doesn't get an error when the type doesn't match.

The listener is a lambda expression that takes an Int type as a parameter.

But listener(addDetailClicked) works normally.

Shouldn't it be listener(Int)? or listener({ i -> addDetailClicked(i) }).

Actually, I don't know why it works even after I write the code.

How is this possible?

Model

@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)
        }
    }
}

Controller

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)
           }

        }
    }
}

Fragment

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)
    }
}

CodePudding user response:

I believe you missed the fact that EpoxyRoutineModel_ contains setters for data types found in EpoxyRoutineModel. For example, EpoxyRoutineModel.curPos is of type Int, so EpoxyRoutineModel_.curPos() is a function declared as:

fun curPos(Int): EpoxyRoutineModel_

(or similar)

Similarly, EpoxyRoutineModel.listener is of type (Int) -> Unit, so EpoxyRoutineModel_.listener() is declared as:

fun listener((Int) -> Unit): EpoxyRoutineModel_

So listener() is a function that receives another function (which itself receives Int). So we can provide addDetailClicked there.

  • Related