Ricardo
Ricardo

Reputation: 8291

Android kotlin - secondary constructor

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?

Upvotes: 0

Views: 4060

Answers (2)

Zoe - Save the data dump
Zoe - Save the data dump

Reputation: 28228

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)
    }
}

Upvotes: 2

zsmb13
zsmb13

Reputation: 89538

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)

}

Upvotes: 1

Related Questions