Kotlin call member Extension function from other class - android

I would like to use this function in multiple classes:
fun <T> T?.ifNull(function: (T?, s:String) -> Unit) {
}
How can I accomplish this?
This is how I would like to use it:
class A{
fun <T> T?.ifNull(function: (T?, s:String) -> Unit) {
}
}
class B{
constructor(){
val a = A()
//I want to use the function here
}}

If you define an extension function as a member of a class A, that extension function is only usable in the context of A. That means, you can use it inside A directly, of course. From another class B though, it's not directly visible. Kotlin has so called scope functions like with, which may be used for bringing your class into the scope of A. The following demonstrates how the extension function is called inside B:
class B {
init {
with(A()) {
"anything".ifNull { it, s -> }
}
}
}
As an alternative, and this is mostly the recommended approach, you would define extension functions top-level, i.e. in a file directly:
fun <T> T?.ifNull(function: (T?, s: String) -> Unit) {
}
class A {
init {
"anythingA".ifNull { it, s -> }
}
}
class B {
init {
"anythingB".ifNull { it, s -> }
}
}

Related

How to convert a object expression to lambda in Kotlin? [duplicate]

This question already has answers here:
Passing lambda instead of interface
(5 answers)
Closed 1 year ago.
I am new to Android development. Recently I am learning Kotlin and I am trying to figure out setOnClickListener. However, I encountered a problem in the process of converting object expression to lambda using Kotlin.
step 1. setOnClickListener in Java:
buttonLogin.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
// my code
}
});
step 2. then I convert Java code to Kotlin code using object expression:
buttonLogin.setOnClickListener(object : View.OnClickListener {
override fun onClick(p0: View?) {
// my code
}
})
step 3. then IntelliJ prompts me to convert object expression to lambda:
buttonLogin.setOnClickListener {
// my code
}
It looks more concise, however, I can't understand the logic behind step 3.
So I checked some information online, it says
Any function that receives an interface with a single function can be
substituted by a lambda
It does on setOnClickListener.
But I still can't fully understand, so I defined an interface and class to verify it.
Here is my code:
interface MyInterface {
fun method1()
}
class MyClass {
fun method2(myInterface: MyInterface) {
myInterface.method1()
}
}
fun main() {
val myClass = MyClass()
myClass.method2(object : MyInterface {
override fun method1() {
println("Hello, world.")
}
})
// So how to write the lambda to replace object expression?
}
The code in step 3 is called trailing lambdas
According to Kotlin convention, if the last parameter of a function is a function, then a lambda expression passed as the corresponding argument can be placed outside the parentheses,
If the lambda is the only argument in that call, the parentheses can be omitted entirely:
For example:
fun function(f : (String) -> Unit) {
}
fun main() {
function {
}
}
Check the Kotlin Documentation for this feature
https://kotlinlang.org/docs/lambdas.html#passing-trailing-lambdas
You can convert your code to use this feature
class MyClass {
fun method2(function: () -> Unit) {
function()
}
}
fun main() {
val myClass = MyClass()
myClass.method2 {
println("Hello, world.")
}
// Or you can store the lambda in variable and use it like tihs
val myClass2 = MyClass()
val function = {
println("Hello, world.")
}
myClass2.method2(function)
}
Or just add convert your interface to a functional interface
fun interface MyInterface {
fun method1()
}
class MyClass {
fun method2(myInterface: MyInterface) {
myInterface.method1()
}
}
fun main() {
val myClass = MyClass()
myClass.method2 {
println("Hello, world.")
}
}

Is there an elegant way to use a class's private variable's method in kotlin?

I'm building a class structure like the following:
class A {
fun methodA() {}
}
class B(private val a: A) {
fun methodB() {}
//fun methodA() { a.methodA() }
}
class C(private val b: B) {
fun methodC() {}
//fun methodB() { b.methodB() }
//fun methodA() { b.methodA() }
}
fun main() {
val c = C(B(A()))
c.methodC()
c.methodA()
c.methodB()
}
Class A is part of class B, and class B is part of class C.
I've commented out the way i'm using the methods. I want to use the methods of class A and B from class C, but every time i add a new method to class A or B, i have to write a function in all the other classes up in the structure, because in the end only class C will be used.

Reuse methods in Kotlin, Android

I need to open one activity from several different points in the app. Let's say from Settings fragment, Main Activity and Navigation drawer (fragment). I don't want to copy/paste the same method and the method is very specific, it should be exactly the same (because it registeres Firebase events). How to structure the code in effective way? Where to put this method? One idea is to have a global ActivityUtils.kt file with just methods and it would be used to store these methods. I'm interested in the alternatives and what are pros and cons of each.
I would create a companion object in the Activity you need to open:
class YourActivity : AppCompatActivity() {
companion object {
fun start(ctx: Context) {
// put your logic here (registering of Firebase events)
val i = Intent(ctx, YourActivity::class.java)
ctx.startActivity(i)
}
}
}
And call it from another activity:
YourActivity.start(this)
or from another fragment:
YourActivity.start(context)
Use an extension method:
fun Activity.doMyStuff() {}
That can be called from any class extending Activity:
doMyStuff()
Extension functions like this shouldn't go inside a class, but rather inside a file. So if you were to make an ActivityUtils.kt file, don't have any sort of class ActivityUtils {} stuff in it. The function(s) should just go directly into the file.
Why not to use MVP?
Like,
interface IView {
val context: Context
}
interface IPresenter {
fun launchActivity(view: IView)
}
class MyActivityModel
{
var key = "key"
/*some other data*/
fun getParcelableObject(): Parcelable
{
return /*some parcelable from model data*/
}
}
class MyActivity : AppCompatActivity(), IView
{
override val context: Context
get() = this
}
class MyActivityPresenter() : IPresenter
{
private var model: MyActivityModel = MyActivityModel()
override fun launchActivity(view: IView)
{
val intent = Intent(view.context, MyActivity::class.java)
intent.putExtra(model.key, model.getParcelableObject())
view.context.startActivity(intent)
}
fun setSomeDataToModel(someData: Any) {
}
}
/*Everyone who wants to use presenter, must be a Context and implement IView*/
fun use()//in some fragment, or activity implementing IView
{
MyActivityPresenter().launchActivity(this)
//or
val presenter = MyActivityPresenter()
presenter.setSomeDataToModel("some data")
presenter.launchActivity(this)
}

Kotlin syntax for LiveData observer?

I have the following bit of code in my HomeActivity to use LiveData.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Show the launch splash screen.
//
this.setContentView(R.layout.activity_home)
this.viewModel = ViewModelProviders.of(this).get(HomeViewModel::class.java)
this.viewModel.getUser().observe(this, Observer { user: User? ->
});
}
While this seems to work, what does the following part mean?
Observer { user: User? ->
}
This must result in an object that conforms to the Observer interface which has
void onChanged (T t)
https://developer.android.com/reference/android/arch/lifecycle/Observer.html
How does
Observer { user: User? ->
}
result in an object with an onChanged method?
I don't know what putting the name of an interface in front of a lambda expression means.
Thanks!
This is called SAM Conversion, a concept that helps interacting with Java Single Abstract Method Interfaces like in your example.
The following creates an implementation of Runnable, where the single abstract method is run():
val runnable = Runnable { println("This runs in a runnable") }
It’s described in the docs: https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
Alternatively, but more verbose, would be to use an object:
val runnable2 = object : Runnable {
override fun run() {
println("This runs in a runnable")
}
}
Both are examples of anonymous implementations of that interface. It's of course also possible to create a concrete subclass and instantiate it then.
class MyRunnable : Runnable {
override fun run() {
println("This runs in a runnable")
}
}
val runnable3 = MyRunnable()
in Kotlin the Observer { } lambda gives you param it, you can rename it as you want and use. by default data will be available with it.something() etc...
JAVA:
... new Observer {
void onChanged(User user){
user.something()
}
}
KOTLIN
... object : Observer<User> {
fun onChanged(user: User){
user.something()
}
}
OR
... Observer {
it.something()
}
you can rename it to whatever you want like
... Observer { myUser ->
myUser.something()
}
To omit the Observer { ... } part just add import androidx.lifecycle.observe and use it like this:
this.viewModel.user.observe(this) { user: User? ->
// ...
}

Pass interface as parameter in Kotlin

I want to pass an interface as parameter like this:
class Test {
fun main() {
test({})
// how can I pass here?
}
fun test(handler: Handler) {
// do something
}
interface Handler {
fun onCompleted()
}
}
In Java, I can use anonymous function like test(new Handler() { .......... }), but I can't do this in Kotlin. Anyone know how to do this?
In Kotlin you can do :
test(object: Handler {
override fun onComplete() {
}
})
Or make a property the same way:
val handler = object: Handler {
override fun onComplete() {
}
}
And, somewhere in code:
test(handler)
since your interface has only one function. you can convert it to SAM like this
fun interface Handler {
fun onCompleted()
}
then you can just implement this interface using lambda instead and so reduce the overall written code. this is only possible in v1.4
Attached is an example of how to pass an object by parameter that represents the value of the data type and invoke behaviors using interface inheritance.
fun main() {
val customClass = CustomClass(
object : First {
override fun first() {
super.first()
println("first new impl")
}
override fun second() {
super.second()
println("second new impl")
}
}
)
customClass.first.first()
customClass.first.second()
}
data class CustomClass(val first: First)
interface First: Second {
fun first() {
println("first default impl")
}
}
interface Second {
fun second() {
println("second default impl")
}
}
It is worth mentioning that with super.first() or super.second() the default behavior of the interface is being invoked.
It doesn't make much sense to pass a lamda with an anonymous object as a parameter, lambda: () -> Unit , if what we need is to invoke the functions.
GL
Playground

Categories

Resources