How do I cast custom MutableLiveData to custom LiveData? - kotlin

suppose there are 2 classes:
class MyLiveData:LiveData<Int>()
class MyMutableLiveData:MutableLiveData<Int>()
Casting from MutableLiveData to LiveData is permitted:
val ld1=MutableLiveData<Int>()
val ld2:LiveData<Int> = ld1 //ok
But you can't cast your own implementations this way:
val mutable=MyMutableLiveData()
val immutable:MyLiveData = mutable //type missmatch
I understand that MutableLiveData extends LiveData thats why they are castable.But I can't have MyMutableLiveData extending MyLiveData as it won't be mutable in this case
Are there any workarounds?
UPD:I guess I need to show motivation of extending LiveData.I'm trying to implement MutableLiveDataCollection which notifies not just value changes via setValue/postValue but also value modification like adding new elements.I'm surprised there is no native solution for this.
Anyway to obseve modify events there have to be additional observe method.And this method have to be inside immutable part aka LiveDataCollection because views will call it.Inheritance is natural solution here IMHO.

The key idea sits in the MutableLiveData class.The only thing this class does - is it changes access modifiers on setValue/postValue methods.I can do the same trick.Therefore the final code will be:
open class LiveDataCollection<K,
L:MutableCollection<K>,
M:Collection<K>>: LiveData<L>() {
private var active=false
private var diffObservers = ArrayList<Observer<M>>()
fun observe(owner: LifecycleOwner, valueObserver: Observer<L>, diffObserver: Observer<M>) {
super.observe(owner,valueObserver)
diffObservers.add(diffObserver)
}
protected open fun addItems(toAdd:M) {
value?.addAll(toAdd)
if (active)
for (observer in diffObservers)
observer.onChanged(toAdd)
}
override fun removeObservers(owner: LifecycleOwner) {
super.removeObservers(owner)
diffObservers= ArrayList()
}
override fun onActive() {
super.onActive()
active=true
}
override fun onInactive() {
super.onInactive()
active=false
}
}
class MutableLiveDataCollection<K,L:MutableCollection<K>,
M:Collection<K>>: LiveDataCollection<K,L,M>() {
public override fun addItems(toAdd:M) {
super.addItems(toAdd)
}
public override fun postValue(value: L) {
super.postValue(value)
}
public override fun setValue(value: L) {
super.setValue(value)
}
}

Related

How can I override onCurrentListChanged of ListAdapter with Kotlin?

I hope to override onCurrentListChanged of ListAdapter, but Code A doesn't work, how can I fix it?
Code A
myAdapter.onCurrentListChanged(){previousList, currentList ->
}
Added Content
To Alexey Romanov: Thanks!
Code C can work well, but Code D by your answer can not work, what error is there?
Code C
private val myAdapter by lazy{
VoiceAdapters(mHomeViewModel,mPlay)
}
Code D
private val myAdapter by lazy{
VoiceAdapters(mHomeViewModel,mPlay) {
override fun onCurrentListChanged(previousList: MutableList<MVoice>, currentList: MutableList<MVoice>) {
}
}
Both
class VoiceAdapters (private val aHomeViewModel: HomeViewModel, private val mPlay: PlayInterface):
ListAdapter<MVoice, VoiceAdapters.VoiceViewHolder>(MVoiceDiffCallback()) {
...
}
The code you show looks more like an attempt to call onCurrentListChanged, but
that would be simply myAdapter.onCurrentListChanged(someList1, someList2);
it probably shouldn't be called manually.
To override a method of ListAdapter, you need to do it when defining myAdapter (or whatever class it's an instance of). E.g.
val myAdapter = object : ListAdapter<SomeType> {
override fun onCurrentListChanged(previousList: MutableList<SomeType>, currentList: MutableList<SomeType>) {
...
}
// other overrides
}
See object expressions for the explanation and details of object : ... syntax.
When you already have myAdapter, it's too late, though you could create a new ListAdapter which has its own onCurrentListChanged and delegates to myAdapter for other methods. Kotlin has special support for this pattern for interfaces, but ListAdapter is a class and you'd have to do everything manually:
val myAdapter2 = object : ListAdapter<SomeType> {
override fun onCurrentListChanged(previousList: MutableList<SomeType>, currentList: MutableList<SomeType>) {
...
}
override fun getCurrentList() = myAdapter.getCurrentList()
override fun getItemCount() = myAdapter.getItemCount()
// etc.
}
Code C can work well, but Code D by your answer can not work, what error is there?
It should be
private val myAdapter by lazy {
object : VoiceAdapters(mHomeViewModel,mPlay) {
override fun onCurrentListChanged(previousList: MutableList<MVoice>, currentList: MutableList<MVoice>) {
}
}
}

This in kotlin interface delegation

Is there any way to pass this when using interface delegation? This would enable nice composability - but I found no way to do this.
Means something like:
interface Foo {
}
class FooImpl(bar: Bar) : Foo {
}
class Bar: Foo by FooImpl(this) {
}
as long as FooImpl doesnt need a parameter like this it works - but it would be great to access the other class there - perhaps someone knows a way. Otherwise I would also be interested if this is worth a KEEP if not - or if it will be impossible for some reason.
Delegation doesn't support this. The delegate has to be instantiated before the class that is delegating to it, so the delegate cannot rely on it for construction. Another gotcha is that although you can override functions of the delegate, if the delegate internally calls those functions, it calls the original version, not the override. The delegate really lives in its own world.
But you could set it up for the host to pass itself to the delegate in its initialization block:
interface Foo<T> {
var host: T
fun doSomething()
}
class FooImpl : Foo<Bar> {
override lateinit var host: Bar
override fun doSomething() {
println(host.name)
}
}
class Bar(val name: String): Foo<Bar> by FooImpl() {
init {
host = this
}
}
fun main() {
val bar = Bar("Hello world")
bar.doSomething()
}
This would unfortunately expose the host to the possibility of getting disconnected from its own delegate by outside classes, though. Maybe you could make the property throw an exception if assigned more than once.
Here's a property delegate that could do that:
private class SingleAssignmentVar<T>: ReadWriteProperty<Any, T> {
private var value: T? = null
private var assigned: Boolean = false
#Suppress("UNCHECKED_CAST")
override fun getValue(thisRef: Any, property: KProperty<*>): T {
if (!assigned)
error("Property has not yet been set.")
return value as T
}
override fun setValue(thisRef: Any, property: KProperty<*>, value: T) {
if (assigned)
error("Property may only be set once.")
assigned = true
this.value = value
}
}
fun <T> Delegates.singleAssignment(): ReadWriteProperty<Any, T> = SingleAssignmentVar()
You may split your Bar class in two parts, say backend and frontend.
Frontend will be responsible for declaring interface with delegates, backend will host delegates and act as composition target.
For example:
interface Foo {
fun sayHello(): String
}
class FooImpl(val bar: BarBackend) : Foo {
override fun sayHello() = "Hello from ${bar.compositionTarget()}!"
}
class BarBackend() {
val fooImpl: FooImpl = FooImpl(this)
fun compositionTarget() = "backend"
}
class BarFrontend(backend: BarBackend) : Foo by backend.fooImpl
fun main() {
val bar = BarFrontend(BarBackend())
println(bar.sayHello())
}

Is there a way to verify that a top-level function passed as a dependency to a class has been called during testing?

I have a class that receives a function allowing it to display things on the UI during a failure case. What's the best way that I can verify that the function is called in my test?
MyClass(private val uiPrinter: (String) -> Unit) {
fun foo() {
// do some stuff
uiPrinter("printing from foo!")
// do some more stuff
}
}
MyClassTest() {
val testUiPrinter: (String) -> Unit = { System.out.println(it) }
#Test
fun uiPrinterIsInvoked() {
val myClass = MyClass(testUiPrinter)
myClass.foo()
// can I verify that testUiPrinter has been invoked?
}
}
You may want to check out the Model-View-Presenter architecture. Its purpose is to hide the Android framework behind an abstract View interface which a purely Java Presenter can interact with. In your example:
interface ViewInterface {
fun printError(error: String)
}
class MyPresenter(private val view: ViewInterface) {
fun foo() {
// do some stuff (testable stuff)
view.printError("Printing from foo()!")
// do some more (testable) stuff
}
}
class MyPresenterTest() { // Test using Mockito to mock the abstract view
private val view = mock(ViewInterface::class.java)
private val presenter = MyPresenter(view)
#Test
fun printsError() {
// set up preconditions
presenter.foo()
verify(view).printError("Printing from foo()!")
}
}
Your concrete view will generally be an Android Activity, Fragment, or View which implements the view interface. Notice MyPresenter only expects the abstract view and does not need knowledge of the framework-dependent operations.
class MyActivity : Activity(), ViewInterface {
// ...
override fun printError(error: String) {
textView.text = error // For example
}
// ...
}
This can be achieved by mocking the higher-order function as higher-order functions are objects unless inlined.
#Mock
val testUiPrinter: (String) -> Unit
#Test
fun uiPrinterIsInvoked() {
val myClass = MyClass(testUiPrinter)
myClass.foo()
verify(testUiPrinter).invoke("Printing from foo!")
}

Kotlin: Can an abstract super class have an abstract constructor?

I have just written this, which is fine as far as it goes:
import com.github.salomonbrys.kotson.get
import com.github.salomonbrys.kotson.int
import com.github.salomonbrys.kotson.jsonObject
import com.google.gson.JsonElement
import com.google.gson.JsonObject
abstract class BatchJobPayload {
abstract fun toJson(): JsonObject
}
class BookingConfirmationMessagePayload(val bookingId: Int) : BatchJobPayload() {
constructor(payload: JsonElement) : this(payload["bookingId"].int)
override fun toJson() = jsonObject(
"bookingId" to bookingId
)
}
But I'd like to insist, if possible, that all classes that extend BatchJobPayload implement a secondary constructor with the signature
constructor(payload: JsonElement): BatchJobPayload, which is to be used for deserializing.
BookingConfirmationMessagePayload has such a constructor but only because I put it there, not because BatchJobPayload insisted upon it...
A workable option I came up with as as follows:
interface BatchJobPayload {
fun toJson(): JsonObject
}
interface BatchJobPayloadDeserialize {
operator fun invoke(payload: JsonElement): BatchJobPayload
}
class BookingConfirmationMessagePayload(val bookingId: Int) : BatchJobPayload {
override fun toJson() = jsonObject(
"bookingId" to bookingId
)
}
class BookingConfirmationMessagePayloadDeserialize : BatchJobPayloadDeserialize {
override operator fun invoke(payload: JsonElement) =
BookingConfirmationMessagePayload(payload["bookingId"].int)
}
Now you can deserialize a BookingConfirmationMessagePayload object from a JsonElement as follows:
BookingConfirmationMessagePayloadDeserialize()(payload)
(The invoke operator is just some syntactic sugar here which may border on the obtuse...)
Actually I still prefer the original code which is less verbose --- a developer needing to subclass BatchJobPayload in the future may initially neglect to define a constructor that takes a JsonElement but they will surely realise their omission once they have just a string of JSON which they need to turn into an instance of their new class...
You can't enforce a super constructor, but you can have factories with a spawn method enforced that returns a subclass of BatchJobPayload, which allows you to make sure classes will be constructable.
It would look something like this:
class JsonObject // Included to make compiler happy
abstract class Factory<T> {
abstract fun make(obj: JsonObject): T
}
abstract class Base {
abstract fun toJson(): JsonObject
}
class A(val data:JsonObject):Base() {
override fun toJson(): JsonObject {
return JsonObject()
}
}
class AFactory: Factory<A>() {
override fun make(obj: JsonObject): A {
return A(obj)
}
}
fun main(args: Array<String>) {
val dummyJson = JsonObject()
var factory = AFactory()
var instance = factory.make(dummyJson)
println(instance)
}

How to overcome "same JVM signature" error when implementing a Java interface?

With the code below, I am getting the following error in IntelliJ IDEA 13.1.6 and Kotlin plugin 0.11.91.AndroidStudio.3:
Platform declaration clash: The following declarations have the same JVM signature (getName()Ljava/lang/String;):
• public open fun getName(): kotlin.String?
• internal final fun <get-name>(): kotlin.String?
Java class, JavaInterface.java:
public interface JavaInterface {
public String getName();
}
Kotlin class, KotlinClass.kt
public class KotlinClass(val name: String?) : JavaInterface
I've tried overriding the 'getter' method by
adding override fun getName(): String? = name, but that produces the same error.
I can see one workaround by doing this instead:
public class KotlinClass(val namePrivate: String?) : JavaInterface {
override fun getName(): String? = namePrivate
}
But in my real-world case I have a number of properties to implement and need setters too. Doing this for each property doesn't seem very Kotlin-ish. What am I missing?
Making that variable private solves the problem.
public class KotlinClass(private val name: String?) : JavaInterface
You could use #JvmField for instructs the compiler not generate getter/setter, and you can implement your setters and getters. With this your code work well in Java (as attribute getter/setter) and Kotlin as property
Example:
JAVA:
public interface Identifiable<ID extends Serializable>
{
ID getId();
}
KOTLIN:
class IdentifiableImpl(#JvmField var id: String) :Identifiable<String>
{
override fun getId(): String
{
TODO("not implemented")
}
}
The annotation feature of Kotlin named #JvmName will solve the duplication problem in Java and Kotlin when having the same signature.
fun function(p: String) {
// ...
}
// Signature: function(Ljava/lang/String)
With the use of JvmName will be:
#JvmName("functionOfKotlin")
fun function(p: String) {
// ...
}
// Signature: functionOfKotlin(Ljava/lang/String)
IMHO most readable combination is field + explicit interface implementation by the single-expression function (combination of #Renato Garcia's and #Steven Spungin's answers):
Java:
public inteface SomeInterface {
String getFoo();
}
Kotlin:
class Implementation(#JvmField val foo: String) : SomeInterface {
override fun getFoo() = foo
}
Another work-around is to declare the properties in an abstract Kotlin class, then write a small java class that extends KotlinClass and implements JavaInterface.
// JavaInterface.java
public interface JavaInterface {
int getFoo();
void setFoo(int value);
}
// KotlinClass.kt
abstract class KotlinClass(open var foo : Int = 0) {
}
// JavaAdapter.java
class JavaAdapter extends KotlinClass implements JavaInterface {
// all code in KotlinClass, but can't implement JavaInterface there
// because kotlin properties cannot override java methods.
}
We have found that to use the same names without clashing, the ctor args must be private AND you must still override the interfaces methods. You don't need any additional backing fields. Also, your expression body assignment will not recurse, so you can safely use that syntax.
Java Interface
interface IUser {
String getUserScope();
String getUserId();
}
Kotlin Class
class SampleUser(private val userScope: String, private val userId: String) : IUser {
override fun getUserId() = userId
override fun getUserScope() = userScope
}
If you have direct control over the interface then the best approach is to write the interface in Kotlin. You can then write your class
public class KotlinClass(override val name: String?) : KotlinInterface
and still reference it from any Java code using the same interface as before. This looks a lot neater than setting all the properties to private and overriding the get function. Obviously if you can't migrate the interface to Java because you don't own it then that seems to be the only solution.
public interface JavaInterface {
public String getName();
}
public class KotlinClass(val namePrivate: String?) : JavaInterface {
private var name = namePrivate
override fun getName(): String? {
return name
}
}
Rename the variable to something else, or make it private if u dont want it to be public.
convert function to property instead of initializing property from a function.
for ex:
fun getCountriesList(): List<Country> {
val countries = mutableListOf<Country>()
countries.add(Country("in", "+91", "India", R.drawable.indian_flag))
countries.add(Country("us", "+1", "United States",R.drawable.us_flag))
return countries
}
to
val countriesList: List<Country>
get() {
val countries = mutableListOf<Country>()
countries.add(Country("in", "+91", "India", R.drawable.indian_flag))
countries.add(Country("us", "+1", "United States", R.drawable.us_flag))
return countries
}