For one permission I can use permissionsdispatcher in java and kotlin - but when it comes to multiple permissions like this:
#NeedsPermission({Manifest.permission.BLUETOOTH_ADMIN,Manifest.permission.BLUETOOTH})
I get a problem on kotlin - it does not accept more than one parameter there - works fine with java
In Java the {} represents creating an array, and in this context in Kotlin the {} is accidentally creating a lambda expression and it cannot be determined what you intend because the code inside the lambda is invalid.
So you are saying #NeedsPermission(someFunctionReferenceThatIsInvalid) instead of passing in an array of permissions as #NeedsPermission(array)
In the annotation the array is being treated as a vararg so you can just list the elements:
#NeedsPermission(Manifest.permission.BLUETOOTH_ADMIN, Manifest.permission.BLUETOOTH)
If it were being treated as an array, you would use the arrayOf function:
#NeedsPermission(arrayOf(Manifest.permission.BLUETOOTH_ADMIN, Manifest.permission.BLUETOOTH))
The examples creating an array and then using the * spread operator are basically doing and then undoing the array and it is not necessary.
#NeedsPermission(arrayOf(Manifest.permission.BLUETOOTH_ADMIN,Manifest.permission.BLUETOOTH))
In java #NeedsPermission({...}) the curly brackets {...} is just a shorthand for creating an array. In kotlin you must explicitly say that it is an array, because {} is reserved for lambda expressions.
Related
I start with one map myInitialMap. i would like to create another map myNewMap that is initialised with myInitialMap.
val myInitialMap = mapOf<String, Int>("one" to 1, "two" to 2)
val myNewMap = mapOf(myInitialMap)
I get error:
Type mismatch.
Required: Pair<TypeVariable(K), TypeVariable(V)>
Found: Map<String, Int>
How can I initialise myNewMap with myInitialMap?
You can use myInitialMap.toList().toMutableStateMap().
The ...Of() functions in Kotlin all follow the convention of taking individual entries as varargs, which is why mapOf(myInitialMap) doesn't, and shouldn't, work. Since these functions use the arguments to determine the generic types, the list/set versions could not possibly support also having overloads that accept an Iterable parameter with all the entries to include, because you might actually want a list of Iterables (2D collection). For consistency, mapOf must behave the same.
Function naming/behavior conventions:
...Of(): A function taking a vararg parameter of all the individual values to put in the collection. The argument type can be used for the compiler to infer the generic type(s) of the collection.
.to...Map/Set/List(): An extension function that creates a shallow copy or new type of collection from the entries of the collection it is called on.
.as...(): An extension function that wraps the original object in another one. For example, asIterable() or asSequence() will return those types, but they will read from the original object. They are not copies.
Passing a lambda to the last parameter
In Kotlin, there is a convention that if the last parameter of a
function accepts a function, a lambda expression that is passed as the
corresponding argument can be placed outside the parentheses:
val product = items.fold(1) { acc, e -> acc * e }
What is the purpose of this syntax?
This syntax gives Kotlin great DSL capabilities, it makes functions look like language constructions. For example:
with(car) {
startUp()
goToDestination()
}
Here with looks like it is language construction, whereas it is a simple function, receiving lambda as the last parameter.
And this leads to such elegant things like Kotlin HTML DSL
I've seen people using ViewModelProvider[Someclass::class.java] instead of ViewModelProvider.get(Someclass::class.java), and it compiles in Android Studio. The problem is that I couldn't find any documentation of such usage online.
With kotlin you can add operator modifiers to your function. So if you have some class with a get function and you might want to access it with [], like an array or map, you could add operator modifier.
Square brackets are translated to calls to get and set with appropriate numbers of arguments.
So this only works for functions with name get or set!
class Provider {
operator fun get(key: String)
operator fun set(key: String, value: String) { ... }
}
Then you can call the function like:
Provider().get("key") // IDE hint: should be replaced with indexing operator
Provider()["key"] // calls get()
Provider().set("key", "value") // IDE hint: should be replaced with indexing operator
Provider()["key"] = "value" // calls set()
Reference
See Kotlin Operator overloading
Kotlin allows operator overloading by marking a function as an operator function. The square brackets notation is one of these operators (indexed access operator).
Kotlin automatically interprets Java functions as operator functions if their name and signature match the requirements of a Kotlin operator function. In this case, it interprets functions named get as an "indexed access operator" if they return something, which allows you to use square bracket notation.
ViewModelProvider[Someclass::class.java] is a shorter version of ViewModelProvider.get(Someclass::class.java) there is no differences.
I am working on Retrofit in Kotlin.
Now, I want to create only one function ( API ) which accepts different pojos as the parameter.
I have created a function with "Any" as parameter.
Now If I try to pass one Model, it gives me compile time error of MyModel cannot convert to Any.
Any suggestions?
Change the parameter type to
Any?
This allows possible null values to be passed. More information about Any vs Any? and interaction with java is shown in this post: kotlin any or kotlin any?
Kotlin introduced inline class which is strong typed type alias. This can be useful when use with database. For example,
inline class Age(val value: Int)
inline class Height(val value: Int)
When they are written to database, they are compiled to Int but Kotlin can prevent you accidentally putting a Height into a Age Field. If you use type alias or Int directly, it is possible with type alias but inline class produces a compile time error.
However, these also cause problems with Android data binding. I get data binding error when I try to bind a String inline class to a String attribute.
While it is possible to write some kinds of adapter to bypass this, but it defeat the purpose of using inline class and not practical for creating adapters for all inline classes.
I would like to ask are there any elegant ways to solve this issue?
First thing you need to understand is inline classes are not just wrappers around primitive types. They are more than type Aliases.
Now coming to your example, even though DataBinding has the understanding that if you put any MutableLiveData<T> instance in xml, it will take that value of that particular variable(something like mutableLiveData.value). But if you put MutablLiveData<Age>, mutableLiveData.value will always be of Type Age but not type Int.
Note that inline class, creates a completely new type and not just a type alias.
I believe that you somehow need a method in your data binding, that returns the value contained in the inline class object.