Lets's say i've this function:
fun createView(binding, type) {
binding.heading_text.text = type
}
And I need this exact function in 2 or more fragments, how can I handle this without duplicate the function every fragment?
You could use utility static class, something like
class MyLogger {
companion object {
fun logNumbers(num1, num2) {
Log.i("MainScreen", "${num1 + num2}")
}
}
}
MyLogger.logNumbers(1, 2)
or inline them
You can create an object with this function.
object Util {
fun createView(binding, type) {
binding.heading_text.text = type
}
And you can use it like this:
Util.createView(binding, type)
Related
I have the following code which i think is valid, because the recursion happens as a result of a callback. It's not called directly as a result of the function call. But the compiler seems to think there is a recursion issue
class Model(callBack: CallBack) {
interface CallBack {
fun onSomething()
}
}
class SomeClass {
fun createModel() = Model(callBack)
val callBack = object : Model.CallBack {
override fun onSomething() {
val anotherModel = createModel()
// Use model for something
}
}
}
Type checking has run into a recursive problem. Easiest workaround: specify types of your declarations explicitly
Is there a workaround for this?
EDIT
I also tried changing callBack to a function so that the same instance is not referenced by multiple models, but I get the same error
The recursive problem mentioned is not about function calls, it's about the compiler trying to find out the types of the declaration and it has stuck in a recursive type checking. It wants to find the output type of createModel which depends on the type of val callback and it depends on createModel again. As it says, declare their types to fix the issue.
class Model(callBack: CallBack)
{
interface CallBack {
fun onSomething()
}
}
class SomeClass {
fun createModel() : Model = Model(callBack)
val callBack : Model.CallBack = object : Model.CallBack {
override fun onSomething() {
val anotherModel : Model = createModel()
// Use model for something
}
}
}
I want to pass 2 different object types to a method to update the view. How can I have this method
accept 2 different object types and access them instead of having 2 different methods for 2 different object types.
I needed something like this -
fun updateView(object: Any<T>) {
//Access the objects here to update the view
}
fun <T : Any> updateView(obj: T) {
//Access the objects here to update the view
}
OR
fun updateView(obj: Any ?= null, obj2:Any ?= null) {
// Access the objects here to update the view
// pass check nullity and use which you want (or not null), other parameter will remain null
obj?.let {
it...
}
obj2?.let {
it...
}
}
Call
updateView(obj1, obj2)
// OR
updateView(obj2 = myObj2)
You can use interfaces for this:
interface ViewInterface {
fun action()
}
class ObjectA : ViewInterface {...}
class ObjectB : ViewInterface {...}
fun updateView(ob: ViewInterface) {
ob.action()
}
try something like this
fun updateView(variable1: Any? = null, variable2:Any? = null) {
//Access the objects here to update the view
}
using named parameters, you can then just set the variables you need when calling the method:
updateView(variable1 = "something")
updateView(variable2 = "something else")
Have your 2 objects implement the same interface or inherit from the same superclass then do something like:
fun updateView(object: MyInterface) {
...
}
Use polymorphism
fun updateView(object: X) {
...
}
fun updateView(object: Y) {
...
}
You can pass two types of object by this way
fun updateView(data:Any? = null,data2:Any?=null) {
//Cast Your Object To your desired type and also can pass null too
// Access the objects here to update the view
}
I would advise separating the two functions, or to use inheritance of some sort to use a single function. But as I see none of those above (which are correct, from the SOLID point of view) satisfies your request, you can just check inside the function based on class.
fun updateView(object: Any) {
when(object){
is Class1Type -> // do whatever fits for the first case
is Class2Type -> // do whatever fits for the second case
else -> // etc.
}
}
The best solution is not related to Kotlin at all. Just make both of them implement an interface and use this interface as the function parameter type.
In general, accepting Any as an input type is not a good practice and using generics is an overkill.
interface DoesStuff
class DoesStuffA: DoesStuff { }
class DoesStuffB: DoesStuff { }
fun doStuff(doer: DoesStuff) {
// do stuff
// if need to distinguish between types
when (doer) {
is DoesStuffA -> // do A
is DoesStuffB -> // do B
}
}
I've pretty excited by Kotlin compiler features and by by in particular - it saves time generating gelegating code:
https://kotlinlang.org/docs/reference/delegation.html
But i want delegate to be nullable and delegating code to check if it's null first and return if it is:
interface Base {
val message: String
fun print()
}
class BaseImpl(val x: Int?) : Base {
override val message = "BaseImpl: x = $x"
override fun print() { println(message) }
}
class Derived(b: Base?) : Base by b {
// This property is not accessed from b's implementation of `print`
override val message = "Message of Derived"
}
fun main() {
val b = BaseImpl(10)
val derived = Derived(b)
derived.print()
println(derived.message)
}
When compiling ^ i'm getting Type mismatch: inferred type is Base? but Base was expected.
Is it still possible with Kotlin?
To be more detailed i'd like Kotlin compiler to generate forwarding calls to wrapped impl (extWebChromeClient) in https://developer.android.com/reference/android/webkit/WebChromeClient like follows:
private WebChromeClient intWebChromeClient = new WebChromeClient()
{
#Override
public void onReceivedTitle(WebView view, String title)
{
if (extWebChromeClient != null)
{
extWebChromeClient.onReceivedTitle(view, title);
}
}
...
You can make this yourself using dynamic proxies, though I wouldn't really recommend it. Note that for non-void methods there's no way to require overriding them. The below implementation just throws exceptions for them unconditionally, but you could still call them for non-null x.
inline fun <reified T : Any> nullableProxy(x: T?): T {
val handler = InvocationHandler { _, method, args ->
if (method.returnType == Void.TYPE) {
if (x != null) {
method.invoke(x, *(args ?: arrayOf()))
}
} else
throw UnsupportedOperationException("Non-void method")
}
return Proxy.newProxyInstance(
T::class.java.classLoader,
arrayOf(T::class.java),
handler) as T
}
class Derived(b: Base?) : Base by nullableProxy(b)
This also won't perform as well as implementing methods directly would.
I'm a bit kotlin newbie and I'm trying to remove the callback instance inside the callback itself.
What I'm trying to achieve it's something similar to the following code.
private val myCallback = SomeInterfaceType {
if(it.something) {
someObject.removeListener(this#SomeInterfaceType)
}
}
Of course it doesn't compile or else I wouldn't be asking here. So I ask, how to remove the callback from inside the instance of the interface?
edit:
the error is "inferred type is X but Y was expected.
edit 2: I just realized I've asked the wrong question, it's similar to it but not exactly a Interface.
The object I'm using have the following constructor/interface
public open class Watcher<T> public constructor(call: (T) -> kotlin.Unit)
so in reality I'm trying to reference the Watcher from inside the call: (T) -> kotlin.Unit to remove the listener.
Is that possible?
You need to use a full object expression syntax to refer to be able to refer to the instance itself:
private val myCallback = object: SomeInterfaceType() {
override fun onSomeEvent() {
if (it.something) {
someObject.removeListener(this)
}
}
}
There's also a workaround: wrap the reference to myCallback into a lambda passed to a function that calls it (e.g. run { ... }):
private val myCallback: SomeInterfaceType = SomeInterfaceType {
if (it.something) {
someObject.removeListener(run { myCallback })
}
}
I'm playing with Kotlin and found interesting behavior.
So lets say i want to have some kind of a Factory :
internal interface SomeStupidInterface {
companion object FACTORY {
fun createNew(): ChangeListener {
val time = System.currentTimeMillis()
return ChangeListener { element -> Log.e("J2KO", "time " + time) }
}
fun createTheSame(): ChangeListener {
return ChangeListener { element -> Log.e("J2KO", "time " + System.currentTimeMillis()) }
}
}
fun notifyChanged()
}
where ChangeListener defined in java file:
interface ChangeListener {
void notifyChange(Object element);
}
And then I try to use it from Java like so:
ChangeListener a = SomeStupidInterface.FACTORY.createNew();
ChangeListener b = SomeStupidInterface.FACTORY.createNew();
ChangeListener c = SomeStupidInterface.FACTORY.createTheSame();
ChangeListener d = SomeStupidInterface.FACTORY.createTheSame();
Log.e("J2KO", "createNew a == b -> " + (a == b));
Log.e("J2KO", "createTheSame c == d -> " + (c == d));
The results are:
createNew: a == b -> false
createTheSame: c == d -> true
I can understand why createNew returns new objects due to closure.
But why I'm receiving the same instance from createTheSame method?
P.S. I know that code above is not idiomatic :)
This has to do with performance. Creating less objects obviously is better for performance, so that is what Kotlin tries to do.
For each lambda, Kotlin generates a class that implements the proper interface. So for example the following Kotlin code:
fun create() : () -> Unit {
return { println("Hello, World!") }
}
corresponds with something like:
Function0 create() {
return create$1.INSTANCE;
}
final class create$1 implements Function0 {
static final create$1 INSTANCE = new create$1();
void invoke() {
System.out.println("Hello, World!");
}
}
You can see here that the same instance is always returned.
If you reference a variable that is outside of the lamdba scope however, this won't work: there is no way for the singleton instance to access that variable.
fun create(text: String) : () -> Unit {
return { println(text) }
}
Instead, for each invocation of create, a new instance of the class needs to be instantiated which has access to the text variable:
Function0 create(String text) {
return new create$1(text);
}
final class create$1 implements Function0 {
final String text;
create$1(String text) {
this.text = text;
}
void invoke() {
System.out.println(text);
}
}
That is why your a and b instances are the same, but c and d are not.
First note: your example code doesn't work as is: the interface has to be written in Java in order to be available for use with SAM constructors.
As for the actual question, you've already touched on why this behavior is happening. Lambdas (in this case, the SAM constructors) are compiled to anonymous classes (unless they're inlined). If they capture any outside variables, then for every invocation, a new instance of the anonymous class will be created. Otherwise, since they don't have to have any state, only a single instance will back every invocation of the lambda. I suppose this is for performance reasons, if nothing else. (Credit to the Kotlin in Action book for the information in this paragraph.)
If you want to return a new instance every time without capturing any variables, you can use the full object notation:
fun createNotQUiteTheSame(): ChangeListener {
return object : ChangeListener {
override fun notifyChanged(element: Any?) {
println("time " + System.currentTimeMillis())
}
}
}
Calling the above function multiple times will return different instances for each call. Interestingly, IntelliJ will suggest converting this to the original SAM conversion syntax instead:
fun createNotQUiteTheSame(): ChangeListener {
return ChangeListener { println("time " + System.currentTimeMillis()) }
}
Which, as you've already found out, returns the same instance every time.
I suppose this conversion is offered because comparing whether these stateless instances are equal is very much an edge case. If you need to be able to do comparison between the instances that are returned, you're probably best off with the full object notation. Then you can even add some additional state to each listener, in the form of an id for example.
it looks like you try to use SAM conversion with Kotlin interface.
Note that SAM conversions only work for interfaces, not for abstract classes, even if those also have just a single abstract method.
Also note that this feature works only for Java interop; since Kotlin has proper function types, automatic conversion of functions into implementations of Kotlin interfaces is unnecessary and therefore unsupported.
For implementing interface like you want, you need to use object expression.
Also look at high order functions - I think you need them for your solution.
internal interface SomeStupidInterface {
interface ChangeListener {
fun notifyChanged(element: Any)
}
companion object FACTORY {
fun createNew(): ChangeListener {
val time = System.currentTimeMillis()
return object : ChangeListener {
override fun notifyChanged(element: Any) {
println("J2KO" + "time " + time)
}
}
}
fun createTheSame(): ChangeListener {
return object : ChangeListener {
override fun notifyChanged(element: Any) {
println("J2KO" + "time " + System.currentTimeMillis())
}
}
}
}
fun notifyChanged()
}
Also In IntelliJ IDEA I can't compile your code.