The Item.kt class is
#Entity(tableName = "item")
class Item(
val id: Long,
val title: String,
) {
#Ignore
var selection: Boolean = false
}
Then i make a query to get all the items in the table ,it return
LiveData<List<Item>>
Then in the viewModel i want to apply selection(true) accordig to the Mutablelivedata selectionId, the selection id contain MutableLiveData<Long> (it contain an id in the LiveData<List<Item>>)
The MyViewModel.kt code is look like this
class MyViewModel(val repository: Repository) : ViewModel() {
..........
......
val selectionId: MutableLiveData<Long> by lazy {
MutableLiveData<Long>()
}
fun setSelectionId(id: Long) {
selectionId.postValue(id)
}
..........
......
val itemLiveList: LiveData<List<Item>> = liveData(Dispatchers.IO) {
emitSource(repository.getItems())
}
}
If it is an List<Item> i can do somethig like this
val ItemWithSelection: List<Item> = repository.getItems().apply {
this.forEach {
if (it.id == selectionId) {
it.selection = true
}
}
}
but i don't know how to achieve this using Mediator LiveData . Please help me
I don't understand everything in your code, for example I have never seen a function called liveData(CoroutineDispatcher). But do you mean you want something like this?
val listWithoutSelection = liveData(Dispatchers.IO) {
emitSource(repository.getItems())
}
val listWithSelection = MediatorLiveData<List<Item>>().apply {
addSource(listWithoutSelection) { updateListSelection() }
addSource(selectionId) { updateListSelection() }
}
fun updateListSelection() {
listWithSelection.value = listWithoutSelection.value?.map {
if (it.id == selectionId.value)
it.copyWithSelection(true)
else
it
}
}
The copyWithSelection could be easily done with Kotlin data classes. It is not needed dependent on whether you want to modify the object you get from the database. If you only use that object here, you could just always reset the selection of the others to false and then you can keep the object and you don't need a copy.
How can I convert the following code to accepted NotNull inside enum class by using Kotlin?
Note: i'm using this enum between two activity and one activity has 2 adapters.
Here is enum class
enum class Adapterx {
ADAPTER_1,
ADAPTER_2;
companion object {
fun fromOrdinal(ordinal: Int): Adapterx? {
return Adapterx.values().firstOrNull { it.ordinal == ordinal }
}
}
}
Since you cannot restrict the ordinal: Int parameter as you've define it, you have two choices if you receive an ordinal which is not part of the enum, or is out of bounds:
Return a default value
Throw an exception
IMHO both cases are plausible if you document properly the method.
Here's a case where you return just a default value if you ask for an ordinal that does not exist:
class KotlinEnumTest {
enum class Adapterx {
ADAPTER_1,
ADAPTER_2;
companion object {
val defaultValue = ADAPTER_1
fun fromOrdinal(ordinal: Int): Adapterx =
Adapterx.values().getOrElse(ordinal, { _ -> defaultValue })
}
}
#Test fun testEnumOrdinals() {
val resultAdapter1 = Adapterx.fromOrdinal(0)
Assert.assertEquals(Adapterx.ADAPTER_1, resultAdapter1)
val resultAdapter2 = Adapterx.fromOrdinal(1)
Assert.assertEquals(Adapterx.ADAPTER_2, resultAdapter2)
// The following returns the default value ADAPTER_1
val resultOrdinalIndexOutOfBounds = Adapterx.fromOrdinal(2)
Assert.assertEquals(Adapterx.ADAPTER_1, resultOrdinalIndexOutOfBounds)
}
}
If you know Google's experimental Android Architecture Components, you probably know MutableLiveData. Trying to make it a bit more fun to use I came with:
class KotlinLiveData<T>(val default: T) {
val data = MutableLiveData<T>()
operator fun getValue(thisRef: Any?, property: KProperty<*>):T {
return data.value ?: default
}
operator fun setValue(thisRef: Any?, property: KProperty<*>, value:T) {
if (Looper.myLooper() == Looper.getMainLooper()) {
data.value = value
} else {
data.postValue(value)
}
}
}
And then I can:
var name : String by KotlinLiveData("not given")
name = "Chrzęszczybrzęczykiewicz"
But alas - that makes data which is needed i.e. to register Observer inaccessible:
name.data.observe(this, nameObserver) // won't work :(
Any idea if I can get it somehow?
You can access the delegate object of the property and get the MutableLiveData<T> from it:
inline fun <reified R> KProperty<*>.delegateAs<R>(): R? {
isAccessible = true
return getDelegate() as? R
}
Then the usage is:
::name.delegateAs<KotlinLiveData<String>>?.data?.observe(this, nameObserver)
To reference a member property, use this::name or someInstance::name.
This solution requires you to add the Kotlin reflection API, kotlin-reflect, as a dependency to your project. Also, due to the type erasure, the .delegateAs<KotlinLiveData<String>> call is not type-safe: it can only check that the delegate is KotlinLiveData<*> but not that its type argument is String.
Thanks to hotkey's solution, here's some better code:
class KotlinLiveData<T>(val default: T, val liveData : MutableLiveData<T>? = null) {
val data = liveData ?: MutableLiveData<T>()
operator fun getValue(thisRef: Any?, property: KProperty<*>):T {
return data.value ?: default
}
operator fun setValue(thisRef: Any?, property: KProperty<*>, value:T) {
if (Looper.myLooper() == Looper.getMainLooper()) {
data.value = value
} else {
data.postValue(value)
}
}
}
inline fun <reified R> KMutableProperty0<*>.getLiveData(): MutableLiveData<R> {
isAccessible = true
return (getDelegate() as KotlinLiveData<R>).data
}
inline fun <reified R> KMutableProperty0<*>.observe(owner: LifecycleOwner, obs : Observer<R>) {
isAccessible = true
(getDelegate() as KotlinLiveData<R>).data.observe(owner,obs)
}
Now I can:
someViewModel::name.observe(myActivity, Observer<String>{...})
with
someViewModel.name = "Kowalski, Leon"
working as expected
This class enables using LiveData with Android Data Binding out of the box.
the simplest way you can achieve is make the delegator to a field, for example:
#JvmField val dataOfName = KotlinLiveData("not given")
var name : String by dataOfName
then you can using live data in the class, for example:
dataOfName.data.observe(this, nameObserver)
name = "Chrzęszczybrzęczykiewicz"
OR you can write some syntax suglar, for example:
var name : String by live("not given").observe(this, nameObserver)
Note you can make nameObserver lazily too, for example:
val observers by lazy{mutableListOf<Observer>()}
var name : String by live("not given").observe(this){data->
observers.forEach{it.dataChanged(data)}
}
then you can do something like as below:
observers+= nameObserver;
name = "Chrzęszczybrzęczykiewicz"
observers-= nameObserver;
I'm trying to find the best way to do a 'reverse lookup' on an enum in Kotlin. One of my takeaways from Effective Java was that you introduce a static map inside the enum to handle the reverse lookup. Porting this over to Kotlin with a simple enum leads me to code that looks like this:
enum class Type(val value: Int) {
A(1),
B(2),
C(3);
companion object {
val map: MutableMap<Int, Type> = HashMap()
init {
for (i in Type.values()) {
map[i.value] = i
}
}
fun fromInt(type: Int?): Type? {
return map[type]
}
}
}
My question is, is this the best way to do this, or is there a better way? What if I have several enums that follow a similar pattern? Is there a way in Kotlin to make this code more re-usable across enums?
First of all, the argument of fromInt() should be an Int, not an Int?. Trying to get a Type using null will obviously lead to null, and a caller shouldn't even try doing that. The Map has also no reason to be mutable. The code can be reduced to:
companion object {
private val map = Type.values().associateBy(Type::value)
fun fromInt(type: Int) = map[type]
}
That code is so short that, frankly, I'm not sure it's worth trying to find a reusable solution.
we can use find which Returns the first element matching the given predicate, or null if no such element was found.
companion object {
fun find(value: Int): Type? = Type.values().find { it.value == value }
}
Another option, that could be considered more "idiomatic", would be the following:
companion object {
private val map = Type.values().associateBy(Type::value)
operator fun get(value: Int) = map[value]
}
Which can then be used like Type[type].
It makes not much sense in this case, but here is a "logic extraction" for #JBNized's solution:
open class EnumCompanion<T, V>(private val valueMap: Map<T, V>) {
fun fromInt(type: T) = valueMap[type]
}
enum class TT(val x: Int) {
A(10),
B(20),
C(30);
companion object : EnumCompanion<Int, TT>(TT.values().associateBy(TT::x))
}
//sorry I had to rename things for sanity
In general that's the thing about companion objects that they can be reused (unlike static members in a Java class)
If you have a lot of enums, this might save a few keystrokes:
inline fun <reified T : Enum<T>, V> ((T) -> V).find(value: V): T? {
return enumValues<T>().firstOrNull { this(it) == value }
}
Use it like this:
enum class Algorithms(val string: String) {
Sha1("SHA-1"),
Sha256("SHA-256"),
}
fun main() = println(
Algorithms::string.find("SHA-256")
?: throw IllegalArgumentException("Bad algorithm string: SHA-256")
)
This will print Sha256
I found myself doing the reverse lookup by custom, hand coded, value couple of times and came of up with following approach.
Make enums implement a shared interface:
interface Codified<out T : Serializable> {
val code: T
}
enum class Alphabet(val value: Int) : Codified<Int> {
A(1),
B(2),
C(3);
override val code = value
}
This interface (however strange the name is :)) marks a certain value as the explicit code. The goal is to be able to write:
val a = Alphabet::class.decode(1) //Alphabet.A
val d = Alphabet::class.tryDecode(4) //null
Which can easily be achieved with the following code:
interface Codified<out T : Serializable> {
val code: T
object Enums {
private val enumCodesByClass = ConcurrentHashMap<Class<*>, Map<Serializable, Enum<*>>>()
inline fun <reified T, TCode : Serializable> decode(code: TCode): T where T : Codified<TCode>, T : Enum<*> {
return decode(T::class.java, code)
}
fun <T, TCode : Serializable> decode(enumClass: Class<T>, code: TCode): T where T : Codified<TCode> {
return tryDecode(enumClass, code) ?: throw IllegalArgumentException("No $enumClass value with code == $code")
}
inline fun <reified T, TCode : Serializable> tryDecode(code: TCode): T? where T : Codified<TCode> {
return tryDecode(T::class.java, code)
}
#Suppress("UNCHECKED_CAST")
fun <T, TCode : Serializable> tryDecode(enumClass: Class<T>, code: TCode): T? where T : Codified<TCode> {
val valuesForEnumClass = enumCodesByClass.getOrPut(enumClass as Class<Enum<*>>, {
enumClass.enumConstants.associateBy { (it as T).code }
})
return valuesForEnumClass[code] as T?
}
}
}
fun <T, TCode> KClass<T>.decode(code: TCode): T
where T : Codified<TCode>, T : Enum<T>, TCode : Serializable
= Codified.Enums.decode(java, code)
fun <T, TCode> KClass<T>.tryDecode(code: TCode): T?
where T : Codified<TCode>, T : Enum<T>, TCode : Serializable
= Codified.Enums.tryDecode(java, code)
Another example implementation. This also sets the default value (here to OPEN) if no the input matches no enum option:
enum class Status(val status: Int) {
OPEN(1),
CLOSED(2);
companion object {
#JvmStatic
fun fromInt(status: Int): Status =
values().find { value -> value.status == status } ?: OPEN
}
}
True Idiomatic Kotlin Way. Without bloated reflection code:
interface Identifiable<T : Number> {
val id: T
}
abstract class GettableById<T, R>(values: Array<R>) where T : Number, R : Enum<R>, R : Identifiable<T> {
private val idToValue: Map<T, R> = values.associateBy { it.id }
operator fun get(id: T): R = getById(id)
fun getById(id: T): R = idToValue.getValue(id)
}
enum class DataType(override val id: Short): Identifiable<Short> {
INT(1), FLOAT(2), STRING(3);
companion object: GettableById<Short, DataType>(values())
}
fun main() {
println(DataType.getById(1))
// or
println(DataType[2])
}
A variant of some previous proposals might be the following, using ordinal field and getValue :
enum class Type {
A, B, C;
companion object {
private val map = values().associateBy(Type::ordinal)
fun fromInt(number: Int): Type {
require(number in 0 until map.size) { "number out of bounds (must be positive or zero & inferior to map.size)." }
return map.getValue(number)
}
}
}
A slightly extended approach of the accepted solution with null check and invoke function
fun main(args: Array<String>) {
val a = Type.A // find by name
val anotherA = Type.valueOf("A") // find by name with Enums default valueOf
val aLikeAClass = Type(3) // find by value using invoke - looks like object creation
val againA = Type.of(3) // find by value
val notPossible = Type.of(6) // can result in null
val notPossibleButThrowsError = Type.ofNullSave(6) // can result in IllegalArgumentException
// prints: A, A, 0, 3
println("$a, ${a.name}, ${a.ordinal}, ${a.value}")
// prints: A, A, A null, java.lang.IllegalArgumentException: No enum constant Type with value 6
println("$anotherA, $againA, $aLikeAClass $notPossible, $notPossibleButThrowsError")
}
enum class Type(val value: Int) {
A(3),
B(4),
C(5);
companion object {
private val map = values().associateBy(Type::value)
operator fun invoke(type: Int) = ofNullSave(type)
fun of(type: Int) = map[type]
fun ofNullSave(type: Int) = map[type] ?: IllegalArgumentException("No enum constant Type with value $type")
}
}
Based on your example, i might suggest removing the associated value and just use the ordinal which is similar to an index.
ordinal - Returns the ordinal of this enumeration constant (its position in its enum declaration, where the initial constant is assigned an ordinal of zero).
enum class NavInfoType {
GreenBuoy,
RedBuoy,
OtherBeacon,
Bridge,
Unknown;
companion object {
private val map = values().associateBy(NavInfoType::ordinal)
operator fun get(value: Int) = map[value] ?: Unknown
}
}
In my case i wanted to return Unknown if the map returned null. You could also throw an illegal argument exception by replacing the get with the following:
operator fun get(value: Int) = map[value] ?: throw IllegalArgumentException()
An approach that reuses code:
interface IndexedEnum {
val value: Int
companion object {
inline fun <reified T : IndexedEnum> valueOf(value: Int) =
T::class.java.takeIf { it.isEnum }?.enumConstants?.find { it.value == value }
}
}
Then the enums can be made indexable:
enum class Type(override val value: Int): IndexedEnum {
A(1),
B(2),
C(3)
}
and reverse searched like so:
IndexedEnum.valueOf<Type>(3)
There is a completely generic solution that
Does not use reflection, Java or Kotlin
Is cross-platform, does not need any java
Has minimum hassle
First, let's define our interfaces as value field is not inherent to all enums:
interface WithValue {
val value: Int
}
interface EnumCompanion<E> where E: Enum<E> {
val map: Map<Int, E>
fun fromInt(type: Int): E = map[type] ?: throw IllegalArgumentException()
}
Then, you can do the following trick
inline fun <reified E> EnumCompanion() : EnumCompanion<E>
where E : Enum<E>, E: WithValue = object : EnumCompanion<E> {
override val map: Map<Int, E> = enumValues<E>().associateBy { it.value }
}
Then, for every enum you have the following just works
enum class RGB(override val value: Int): WithValue {
RED(1), GREEN(2), BLUE(3);
companion object: EnumCompanion<RGB> by EnumCompanion()
}
val ccc = RGB.fromInt(1)
enum class Shapes(override val value: Int): WithValue {
SQUARE(22), CIRCLE(33), RECTANGLE(300);
companion object: EnumCompanion<Shapes> by EnumCompanion()
}
val zzz = Shapes.fromInt(33)
As already mentioned, this is not worth it unless you have a lot of enums and you really need to get this generic.
Came up with a more generic solution
inline fun <reified T : Enum<*>> findEnumConstantFromProperty(predicate: (T) -> Boolean): T? =
T::class.java.enumConstants?.find(predicate)
Example usage:
findEnumConstantFromProperty<Type> { it.value == 1 } // Equals Type.A
val t = Type.values()[ordinal]
:)