How can I set a function to be used in a custom co...
# android
j
How can I set a function to be used in a custom control? I can expose and bind to properties like strings, ints, etc, but how can I do the same for a function?
a
Like a listener?
j
yes
a
In you class, create a setter function where you can pass in a function
like this
Copy code
fun setListener(l: () -> Unit) {
    listenerVar = l;
}
then you can invoke listenerVar
I recommend setting up listenerVar like:
Copy code
private var listener: Unit -> () = {}
to avoid NPEs
j
How do I access that from my xml? So far I've been using attrs file to create properties
a
Ohhh
I thought you meant an event listener
In java/kotlin
j
Well the listener is already in the button which is part of my control
but I must set it
from the control binding
a
Are you using databinding?
j
yes
a
Ah, not that familiar with it then
Refer here then
j
Perhaps the variable can be used
<data> <variable name="handlers" type="com.example.MyHandlers"/> <variable name="user" type="com.example.User"/> </data>
a
yes, like that
j
Not sure if there's type for any function though
a
Put the function in a class
j
well it's going to be in a viewmodel probably
and I was hoping to disconnect the control from viewmodel
to let it be used however I want. It's nicer code
At first it was just a view I included but I transformed it into a control and was able to expose some properties to bind to instead.
Now I just need to expose an onDeclineButtonClick property where I can set it to a function to be used
a
I would personally keep it as a view
Or
have the XML and inflate it wherever it needs to go
but that’s me
I’m not as familiar with viewbinding
j
Well that worked, I did it from the start but I like this way more since you could put some behavior into the control itself, and it can be used anywhere.
It should be possible to expose the method, the Button class does it for example..
a
I’m used to the oldschool way of doing things 😜
Idk how to help you with the viewbinding thing
j
Yeah I'm trying the new way with viewmodels and bindings. It's nice clean code once you get it working
a
Can’t you pass in a viewmodel as a variable?
j
I did that when I just included the view
but I wanted to separate them
so I can have logic also in the control if I want
like animations etc
a
You can add animation to a view 😜
j
ah
a
Just inflate a layout into your view
j
well it can be separated from the viewmodel at least. What if I also want to use it in another view?
a
and you can reference the view IDs and animate them, etc
j
I don't, but still. It's better to separate if possible
I wonder how the button class does it
a
I guess I’d have to see the use case, dunno why you’d want to separate it
You mean like how button has onclick in XML?
j
well I have a viewmodel with currentPrice and description etc
It's not the controls viewmodel, the control just happens to in this case be inside the view that uses that viewmodel
but what if I wanted to put it in another view?
and yes
like it has onClick in XML
a
They use reflection
So you pass in the member name, it has to be inside the same class
and It’ll call the method
It’s actually in View.java
j
the class that inflates the view?
a
The onClick XML property code is held in the View class itself
Screen Shot 2019-11-06 at 5.58.39 PM.png
DeclaredOnClickListener will use reflection based on the current activity
or context
That’s the problem there with passing it in XML
you’d have to have the class
member
etc
Then you’d use reflection which is a mess
j
hm
They seem to pass handlerName as a string
The question is where that handler is declared
Because I could certainly declare a handlerName too
Maybe I should just pass the viewmodel for the parent view. Was hoping for a nicer solution where the control is independent of the parent
a
You can create an interface with the onclick implementation in your activity/fragment, then set it as a variable to the binding layout. Then call the methods from that interface directly from xml like so android:onClick="@{() -> interface.onButtonClicked()}"
And you will have a <variable name="interface"> with type MyInterface (for example) in your xml Disclaimer variable creation is psudo code
a
I think you are tightly coupling more things together than you need
a
Xml and activity are parts of your "view" as they are , so how can you decouple them?
And the part of databinding when you are bringing expressions into xml (binding expressions) are also coupling and adding logic to xml, you can argue that it is not right but if you look at those expressions (most of them are conditional) that's what they are...logic
j
I ended up adding an interface class for the function
Copy code
class FindJobsViewModel : BaseViewModel() {
    var onDeclineButtonClickedCommand = object: ICommand {
        override fun execute() {
            nextCard()
        }
    }
in attrs file I add <attr name="onDeclineButtonClickedCommand" />
and in SellerJobCard class:
Copy code
fun setOnDeclineButtonClickedCommand(command: Command) {
        onDeclineButtonClickedCommand = command
    }
Copy code
init {
        button_decline.setOnClickListener {
            onDeclineButtonClickedCommand?.execute()
        }
    }
and then I bind to that in the xml