I want to implement a class with two constrcutors. And empty constructor and another with a param user:FirebaseUser
But i'm getting the message error:
"There is a cycle in the delegation change"
class UserModel(user: FirebaseUser) {
var uid: String?
val email: String?
val phoneNumber: String?
val photoUrl: String
val displayName: String?
//error message: There is a cycle in the delegation change
constructor():this() {}
init {
this.displayName = user.displayName
this.email = user.email
this.phoneNumber = user.phoneNumber
this.photoUrl = user.photoUrl!!.toString()
this.uid = user.uid
}
companion object {
#Exclude
val CURRENT_LOCATION = "location"
}
}
I've tried several approaches without success. Any help?
All the secondary constructors have to call the primary constructor, either directly or indirectly. Which means:
class X(var x: Int){
constructor() : this(0.0);
constructor(x: Double) : this(x.toInt());
}
However, you can't do this:
class X(var x: Int){
constructor() : this();
constructor(x: Double) : this();
}
Because it would result in a Stack Overflow Exception.
The above example is horrible code, but it's just as a demo.
So with this line:
constructor():this() {}
You make the secondary constructor call itself.
Instead, call the primary constructor. This means you need to pass a FirebaseUser as an argument. I'm not familiar with Firebase, so I'll leave that to you.
But as an example, you basically need to do this instead:
constructor() : this(FirebaseUser());
Either initialize directly, or get it from a method. If you can't get one, you could of course just make it nullable.
But if you're dealing with nullables, assuming the majority of your code is in Kotlin, you can just make it nullable with a default value and remove the secondary constructor:
class UserModel(user: FirebaseUser? = null){
init{
// Now that `user` is nullable, you need to change the assignments to include null-safe or non-null assertion (?. or !!. respectively)
}
}
You have to call into the primary constructor from every secondary constructor you have, since its parameters may be used in property initializers and initializer blocks, like you've used user in the init block in your code.
With this code, the secondary constructor just recursively calls itself:
constructor() : this() {}
What you should do instead is call into the primary constructor so that the class' properties can be initialized:
constructor() : this(FirebaseUser()) {} // get FirebaseUser from somewhere
Alternatively, if what you meant to do is leave everything null when the secondary no-param constructor is called, you could opt for something like this:
class UserModel(user: FirebaseUser?) {
var uid: String? = user?.uid
val email: String? = user?.email
val phoneNumber: String? = user?.phoneNumber
val photoUrl: String? = user?.photoUrl?.toString()
val displayName: String? = user?.displayName
constructor() : this(null)
}
Related
https://github.com/neuberfran/JThings/blob/main/app/src/main/java/neuberfran/com/jfran/model/FireFran.kt
I have this POJO above with the error mentioned in the topic. I know it is a mistake already mentioned here, but I have tried several classes (besides this one) and I have not been successful, since my model/POJO class (and Code implementation) is different from several that I saw:(Every help is welcome)
Could not deserialize object. Class does not define a no-argument
constructor. If you are using ProGuard, make sure these constructors
are not stripped (found in field 'value')
Change made to the garagem document, exchanged value for valorb, etc...
The error is very clear, your class "FireFran" doesn't have a no-argument constructor. When you try to deserialize an object from Cloud Firestore, the Android SDKs require that the class must have a default no-arg constructor and also setters that map to each database property.
In Kotlin, the data classes don't provide a default no-arg constructor. So you need somehow ensure the compiler that all the properties have an initial value. You can provide to all of the properties an initial value of null or any other value you find more appropriate.
So your "FireFran" might look like this:
class FireFran(
var alarmstate: Boolean = false,
var garagestate: Boolean = false,
var id: String? = null,
var userId: String? = null,
var value: FireFranValue? = null //Newly added
) {
//var value: FireFranValue = FireFranValue(false, 0)
companion object Factory {
fun create() :FireViewModel = FireViewModel()
var COLLECTION = "device-configs"
var DOCUMENT = "alarme"
var FIELD_userId = "userId"
}
}
Now adding the properties in the constructor, Kotlin will automatically generate a default no-arg constructor. In this way, the Firebase Android SDK will be able to use. It will also generate setters for each property. Please see that each property is var and not a val, and provides a default null value in case of "id" and "userId".
If don't make this change, you won't be able to use automatic deserialization. You'll have to read the value for each property out of the DocumentSnapshot object and pass them all to Kotlin's constructor.
Edit:
In your screenshot, the "value" property is on an object of type "FireFranValue", which has only two properties, "brightness" and "on". To be able to read the data under "value", your "FireFran" class should contain a new property of type "FireFranValue". Please check above the class.
If you don't want to use automatic deserialization, you can get the value of each property individually. For example, you can get the value of the "userId" property using DocumentSnapshot's getString(String field) method:
val userId = snapshot.getString("userId")
Edit2:
Your three classes should look like this:
class FireFran(
var alarmstate: Boolean = false,
var garagestate: Boolean = false,
var id: String? = null,
var userId: String? = null,
var owner: String? = null,
var value: FireFranValue = FireFranValue(false),
var valorb: FireFranValueB = FireFranValueB(openPercent = 0)
)
data class FireFranValue(
var on: Boolean // = false
)
data class FireFranValueB(
var openPercent: Number // = 0
)
Edit3:
class FireFran(
var alarmstate: Boolean = false,
var garagestate: Boolean = false,
var id: String? = null,
var userId: String? = null,
var owner: String? = null,
var value: FireFranValue? = null,
var valorb: FireFranValueB? = null
)
data class FireFranValue(
var on: Boolean? = null
)
data class FireFranValueB(
var openPercent: Number? = null
)
Now, "on" and "openPercent" will get the values from the database.
Please check the following class declaration:
You can define a no-arg constructor in kotlin like this:
data class SampleClass(
val field1: String,
val field2: String
) {
constructor(): this("", "")
}
First thing: It was not necessary to create the field (map type) called valorb. It was resolved with value.openPercent
As I have two documents (alarme and garagem) I created two POJO classes (FireFran and FireFranB)
https://github.com/neuberfran/JThingsFinal/blob/main/app/src/main/java/neuberfran/com/jfran/model/FireFranB.kt
The secret was to treat the value.on and value.openPercent fields as maps (as facts are):
https://github.com/neuberfran/JThings/blob/main/app/src/main/java/neuberfran/com/jfran/model/FireFran.kt
I have this POJO above with the error mentioned in the topic. I know it is a mistake already mentioned here, but I have tried several classes (besides this one) and I have not been successful, since my model/POJO class (and Code implementation) is different from several that I saw:(Every help is welcome)
Could not deserialize object. Class does not define a no-argument
constructor. If you are using ProGuard, make sure these constructors
are not stripped (found in field 'value')
Change made to the garagem document, exchanged value for valorb, etc...
The error is very clear, your class "FireFran" doesn't have a no-argument constructor. When you try to deserialize an object from Cloud Firestore, the Android SDKs require that the class must have a default no-arg constructor and also setters that map to each database property.
In Kotlin, the data classes don't provide a default no-arg constructor. So you need somehow ensure the compiler that all the properties have an initial value. You can provide to all of the properties an initial value of null or any other value you find more appropriate.
So your "FireFran" might look like this:
class FireFran(
var alarmstate: Boolean = false,
var garagestate: Boolean = false,
var id: String? = null,
var userId: String? = null,
var value: FireFranValue? = null //Newly added
) {
//var value: FireFranValue = FireFranValue(false, 0)
companion object Factory {
fun create() :FireViewModel = FireViewModel()
var COLLECTION = "device-configs"
var DOCUMENT = "alarme"
var FIELD_userId = "userId"
}
}
Now adding the properties in the constructor, Kotlin will automatically generate a default no-arg constructor. In this way, the Firebase Android SDK will be able to use. It will also generate setters for each property. Please see that each property is var and not a val, and provides a default null value in case of "id" and "userId".
If don't make this change, you won't be able to use automatic deserialization. You'll have to read the value for each property out of the DocumentSnapshot object and pass them all to Kotlin's constructor.
Edit:
In your screenshot, the "value" property is on an object of type "FireFranValue", which has only two properties, "brightness" and "on". To be able to read the data under "value", your "FireFran" class should contain a new property of type "FireFranValue". Please check above the class.
If you don't want to use automatic deserialization, you can get the value of each property individually. For example, you can get the value of the "userId" property using DocumentSnapshot's getString(String field) method:
val userId = snapshot.getString("userId")
Edit2:
Your three classes should look like this:
class FireFran(
var alarmstate: Boolean = false,
var garagestate: Boolean = false,
var id: String? = null,
var userId: String? = null,
var owner: String? = null,
var value: FireFranValue = FireFranValue(false),
var valorb: FireFranValueB = FireFranValueB(openPercent = 0)
)
data class FireFranValue(
var on: Boolean // = false
)
data class FireFranValueB(
var openPercent: Number // = 0
)
Edit3:
class FireFran(
var alarmstate: Boolean = false,
var garagestate: Boolean = false,
var id: String? = null,
var userId: String? = null,
var owner: String? = null,
var value: FireFranValue? = null,
var valorb: FireFranValueB? = null
)
data class FireFranValue(
var on: Boolean? = null
)
data class FireFranValueB(
var openPercent: Number? = null
)
Now, "on" and "openPercent" will get the values from the database.
Please check the following class declaration:
You can define a no-arg constructor in kotlin like this:
data class SampleClass(
val field1: String,
val field2: String
) {
constructor(): this("", "")
}
First thing: It was not necessary to create the field (map type) called valorb. It was resolved with value.openPercent
As I have two documents (alarme and garagem) I created two POJO classes (FireFran and FireFranB)
https://github.com/neuberfran/JThingsFinal/blob/main/app/src/main/java/neuberfran/com/jfran/model/FireFranB.kt
The secret was to treat the value.on and value.openPercent fields as maps (as facts are):
Well, I've a situation, where in Class A I get "X DATA".
I want to store this "X DATA" in Object X one time and then make sure, the values of this object is not possible to change. (Set it once and forget about it).
My approach:
object X {
var attribute1: String
var attribute2: String
}
Obviously, as object attributes are var they are changeable in future. How could I avoid this? Is there a way to assign values (in some time..) and then lock the object till application is exited?
You could use a delegate property
class MyProperty<T : Any> {
private var value: T? = null
operator fun getValue(myObject: MyObject, property: KProperty<*>): T =
value ?: throw UninitializedPropertyAccessException()
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: T) = when (this.value) {
null -> this.value = value
else -> throw IllegalAccessException("Property already initialized")
}
}
and then use var in your object
object MyObject {
var myProperty by MyProperty<String>()
}
In the sample above, if you try to access myProperty before setting a value, an exception is thrown, but you could handle that as you wish (return a default value? maybe null?).
If you try to assign the value more than once, you get an exception as well but you could handle that differently, for instance, by simply not setting the value anymore so that
MyObject.myProperty = "foo"
MyObject.myProperty = "bar"
println(MyObject.myProperty)
will print "foo"
You can use lateinit var attribute1: String to tell the compiler that you will manage setting attribute1 to a non-null value before it's used.
There's no such thing as lateinit val to "lock" the value as you say.
The docs have more information.
I suggest you make those properties final by replacing var with val.
var is like general variable and its known as a mutable variable in kotlin and can be assigned multiple times.
val is like constant variable and its known as immutable in kotlin and can be initialized only single time.
You can't lateinit immutable properties in kotlin and lateinit var does not allow custom setters.
So my approach would be implementing the lateinit var behavior with a backing property, custom getter and custom setter. This is quite a similar approach to lellomans solution.
object X {
private lateinit var backingprop: String
var attribute: String
set(arg) {
if (this::backingprop.isInitialized) throw IllegalAccessException("Property already initialized")
backingprop = arg
}
get() = backingprop
}
I warn you! But you can use such example:
object Immutable {
val immutableString: String = mutableStaticString ?: "some default value, just in case"
}
var mutableStaticString: String? = null
class App : Application() {
override fun onCreate() {
super.onCreate()
mutableStaticString = "hello duct tape solutions!"
android.util.Log.d("ductTape", mutableStaticString)
android.util.Log.d("ductTape", Immutable.immutableString)
}
}
Right code:
class MainActHandler(val weakActivity: WeakReference<Activity>): Handler() {
override fun handleMessage(msg: Message?) {
val trueAct = weakActivity.get() ?: return
if (msg?.what == ConversationMgr.MSG_WHAT_NEW_SENTENCE){
val sentence = msg.obj as String?
trueAct.conversation.text = sentence
}
super.handleMessage(msg)
}
}
cannot be resolved code:
class MainActHandler(weakActivity: WeakReference<Activity>): Handler() {
override fun handleMessage(msg: Message?) {
val trueAct = weakActivity.get() ?: return
if (msg?.what == ConversationMgr.MSG_WHAT_NEW_SENTENCE){
val sentence = msg.obj as String?
trueAct.conversation.text = sentence
}
super.handleMessage(msg)
}
}
cannot be resolved code screenshot
The only difference is the "val" has been deleted and cannot be resolve.
Which might be important is that it's a inner class.
BUT
This one class without "val/var" in constructor parameter is working:
class BookInfo(convrMgr: ConversationMgr, id: String, queue: RequestQueue, queueTag:String) {
val TAG = "BookInfo"
var title: String? = ""
init {
val url = "https://api.douban.com/v2/book/$id"
// Request a string response from the provided URL.
val stringRequest = StringRequest(Request.Method.GET, url,
Response.Listener<String> { response ->
Log.d(TAG + " Response", response.substring(0))
// Parse JSON from String value
val parser = Parser()
val jsonObj: JsonObject =
parser.parse(StringBuilder(response.substring(0))) as JsonObject
// Initial book title of book properties.
title = jsonObj.string("title")
Log.d(TAG + " Book title", title)
convrMgr.addNewMsg(title)
},
Response.ErrorListener { error -> Log.e(TAG + " Error", error.toString()) })
// Set the tag on the request.
stringRequest.tag = queueTag
// Add the request to the RequestQueue.
queue.add(stringRequest)
}
}
And if I add var/val before "queue: RequestQueue", I'll get suggestion:
"Constructor parameter is never used as a property less. This inspection reports primary constructor parameters that can have 'val' or 'var' removed. Unnecessary usage of 'val' and 'var' in primary constructor consumes unnecessary memory."
I am just confused about it.
When you write val/var within the constructor, it declares a property inside the class. When you do not write it, it is simply a parameter passed to the primary constructor, where you can access the parameters within the init block or use it to initialize other properties. For example,
class User(val id: Long, email: String) {
val hasEmail = email.isNotBlank() //email can be accessed here
init {
//email can be accessed here
}
fun getEmail(){
//email can't be accessed here
}
}
Constructor parameter is never used as a property
This suggestion is saying that you do not use this property in place apart from the initialization. So, it suggests you to remove this property from the class.
Constructor parameters must use var or val when they are used as a property elsewhere in the class. They do not need to be properties if they are only used for class initialization.
In the example below, the parameter must be a property (var or val) because it is used in a method:
class A(val number: Int) {
fun foo() = number
}
In this other example, the parameter is only used to initialize the class, so it does not need to be a property:
class B(number: Int): A(number) {
init {
System.out.println("number: $number")
}
}
This might be a late answer but the magic lies under the hood:
Based on #BakaWaii's answer:
Putting var/val will make the variable a property of the class and not putting it will make it a parameter of only the constructor function.
So what does it mean, to understand lets look into some code:
class Test(a: Int){}
Now Lets see the decompiled java code:
public final class Test {
public Test(int a) {
}
}
So now if I try to access a using the object of Test() like the below code:
Test t = new Test(10);
t.a //Error
It will give me error. Unresolved reference: a. Why because a is a parameter of the constructor only.
Now if we put var/val in the paramater like below:
class Test(var a: Int){}
The decompliked Java code will become:
public final class Test {
private int a;
public final int getA() {
return this.a;
}
public final void setA(int var1) {
this.a = var1;
}
public Test(int a) {
this.a = a;
}
}
Thus it will not only give you a class property but also give you getter/setters for setting the values.
Now the next question arises if the field a is private how can it be accessed. Simple answer in Java you cannot, i.e. if you are calling the KT class from a Java you will not be able to assign value of a like Test(1).a = 10 but will have to use Test(1).setA(5).
But as kotlin internally handles getters/setters Test(1).a = 5 will be ok.
For #Parcelize to work you need to open up the super's properties and override them in the child:
abstract class Goal(open var number: Int, open var name: String) : Parcelable
#Parcelize
class OperationalGoal(override var number: Int, override var name: String, var description: String) : Goal(number, name)```
In very simple terms, use var or val in class constructor parameters when you want to use that variable, say, inside a method within that class. Thus you're effectively turning them into properties and not just mere constructor or method parameters.
class User(var name: String, age: Int) {
var str = "John"
var num = 18
fun setName(){
name = str // due to using var on our class constructor parameter, we can access the constructor variable *name* inside this setter method. *name* is a property parameter thanks to the var keyword.
}
fun setAge(){
age = num // this will result in a compiler error, because *age* is just a parameter, notice that var wasn't used in the *age* parameter within the class constructor, which means we can't access it like we did with *name*
}
}
Run this Kotlin Playground code to get a clearer idea of what's going on.
As i have one User class having 2 parameters : first_name, last_name. So my kotlin class with be :
data class User(val first_name:String, val last_name:String)
Now i want a constructor which will accept only first_name, or you can say just one parameter. How can i define it with Kotlin?
I know we can pass default value and in that way we can ignore second parameter, but how can we write multiple constructor?
You can define extra constructors in the class body
data class User(val firstName: String, val lastName: String) {
constructor(firstName: String) : this(firstName, "")
}
These 'secondary constructors' have to call through to the primary constructor or a different secondary constructor. See the Official documentation on constructors.
So, in effect this is the same as just a primary constructor with default argument, which would be the idiomatic way to go.
data class User(val firstName: String, val lastName: String = "")
I hope this will help you
class Person(val name: String, val age: Int = 0) {
override fun toString(): String {
return name + " is " + age + " years Old"
}
}
fun main(args: Array<String>) {
var person = Person(name = "vignesh")
var personNew = Person("vignesh", 23)
println(person.toString())
println(personNew.toString())
}
Output
vignesh is 0 years Old
vignesh is 23 years Old
If you are using data class, then you won't require another constructor. Just pass default value to your last_name parameter.
If you are using a normal class then you can have secondary constructor
Lets say you have class A
class A(val param:String,val param2:String){
constructor(val param:String):this(param,"")
}
If you wish manipulate these values you can use init{} block where you can play around your constructor values.
I hope this will help.
A class in Kotlin can have a primary constructor and one or more secondary constructors. The primary constructor is part of the class header: it goes after the class name (and optional type parameters).
class Person constructor(firstName: String) {
}
If the primary constructor does not have any annotations or visibility modifiers, the constructor keyword can be omitted:
class Person(firstName: String) {
}
Note that parameters of the primary constructor can be used in the initializer blocks. They can also be used in property initializers declared in the class body:
class Customer(name: String) {
val customerKey = name.toUpperCase()
}
You can also follow this link as per your need : Kotlin
This sample of code works fine for me, you can customize them to your need.
data class Booking(
var user: String,
var bike: String
){
constructor(
user: String,
bike: String,
taken_at: String,
returned_at: String
) : this (user, bike)
}