is there a way of bundling function references in Kotlin and Android so that the functions can be called from other fragments? For instance, my fragment factory method looks like this:
fun newInstance(tryAgainFunction: () -> Unit): TimeOutHandlerFragment {
val fragment = TimeOutHandlerFragment()
val bundle = Bundle()
return fragment
}
I want to be able to save my tryAgainFunction in the bundle for further retrieval.
Thanks a lot!
Edit
In the end, the most suitable solution was using hotkey's answer and then in onViewCreated I initializing a listener with the passed function. The complete code is as follows:
companion object {
val CALLBACK_FUNCTION: String = "CALLBACK_FUNCTION"
fun newInstance(tryAgainFunction: () -> Unit): TimeOutHandlerFragment {
val fragment = TimeOutHandlerFragment()
val bundle = Bundle()
bundle.putSerializable(CALLBACK_FUNCTION, tryAgainFunction as Serializable)
fragment.arguments = bundle
return fragment
}
}
override fun onViewCreated(view: View?, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
try {
val callback: () -> Unit = arguments.getSerializable(CALLBACK_FUNCTION) as () -> Unit
btnTryAgain.setOnClickListener { callback.invoke() }
} catch (ex: Exception) {
// callback has a wrong format
ex.printStackTrace()
}
}
Thanks to everyone for your help!
If tryAgainFunction
is Serializable
, then you can put it into the bundle
using bundle.putSerializable("try_again_function", tryAgainFunction);
.
It will actually be Serializable
if it is a function reference (SomeClass::someFunction
) or a lambda. But it might not be, if it is some custom implementation of the functional interface () -> Unit
, so you should check that and handle the cases when it's not.
2022 Update:
NotSerializableException
.Fragment
in the other, that is FragmentResultListener
, offical tutorial is here: https://youtu.be/oP-zXjkT0C0?t=468.FragmentResultListener
cannot meet your need, Shared ViewModel
is the final solution in there: https://youtu.be/THt9QISnIMQ.1. You need to add id 'kotlin-parcelize'
to your build.gradle (app), like this:
plugins {
id 'com.android.application'
id 'kotlin-android'
id 'kotlin-kapt'
id 'kotlin-parcelize' //here
}
2. Create a Class to wrap your Lambda function:
@Parcelize
class Listener(val clickAction: () -> Unit) : Parcelable {
fun onClick() = clickAction()
}
3. Pass your Lambda:
val bundle = Bundle().apply {
putParcelable("listener", Listener(clickAction))
}
private val clickAction: () -> Unit = {
//do your stuff
}
4. Retrieve it:
arguments?.getParcelable<Listener>("listener")?.onClick()
Demo (all Fragment
s): https://youtu.be/0OnaW4ZCnbk
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With