Constructor overloading with Kotlin - android

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

Related

Kotlin apply function with data class

I have a data class like this -
data class User(val id: String, val name: String)
I want to use apply scope function to modify the values and return the modified object.
User("1", "Name").apply {
this.id = "2" // Gives me error since val cannot be assigned
}
I do not want to make my data class immutable and also don't want to use copy function. How do I fix this?
You can use copy method with data classes:
val user1 = User("1", "Name")
val user2 = user1.copy(id = "2")
change like this data class User(var id: String, var name: String)

why are variables initialized in data class

According to the official doc, this is the way to declare a data class
data class User(val name: String, val age: Int)
but most cases i see where data class is declared thus,
data class User(var username: String? = "", var email: String? = "", var age: Int = 0)
explanation from the docs: On the JVM, if the generated class needs to have a parameterless constructor, default values for all properties have to be specified
i don't understand, and what are the implications of the different methods
2ndly, what is the best way of writing a data class containing complex object variables such as, ArrayList, Bitmap, Uri
A parameterless constructor would probably only be necessary if you were using the class with some library that generates instances of your class through reflection, such as a serialization library or dependency injection library.
If you put = and some value after a constructor parameter, it allows you to omit that parameter when calling the constructor. The value you put there will be the default value used when the parameter is omitted. This is usually used as a convenience. But if you are using one of the aforementioned libraries, you would also need an empty constructor. By providing defaults for every parameter and annotating the primary constructor with #JvmOverloads, you can satisfy this requirement. It would look like this:
data class User #JvmOverloads constructor(var username: String? = "", var email: String? = "", var age: Int = 0)
If your data class has a lot of properties, you may not want to use #JvmOverloads because the number of constructors it generates is exponentially proportional to the number of properties with defaults. Instead, you can define a secondary constructor like this:
data class User(var username: String?, var email: String?, var age: Int) {
constructor(): this("", "", 0)
}
Your second question is very open-ended and opinion-based, so near-impossible to answer in a helpful way.

How to access primary constructor parameters inside secondary constructor kotlin

I am learning kotlin and I was reading about constructors: primary and secondary.
Here is my question that how should I access primary constructor parameters inside a secondary constructor. I am unable to access but I am not sure why? Why I am not able to access it directly?
If anyone knows please help me understand this concept in a better way. Why I am not able to access it?
I have created one demo class with two constructors here is my code:
fun main(args: Array<String>) {
val person1 = Person("Joe", 25)
println("First Name = ${person1.firstName}") // working, printing first name
}
class Person(val firstName: String, var age: Int) {
constructor(sectionName: String, id: Int, name: String) : this(sectionName,id) {
println("Age = ${age}") // not working, no output
}
}
Or Am I doing anything wrong?
PS: I know I can write init block and assign the parameters to the class variable and it is working as expected.
You have to call your secondary constructor, which expects a trailing name parameter:
val person1 = Person("Joe", 25, "name") //prints Age = 25
val person2 = Person("Joe", 25) //prints nothing
In your example, the primary constructor gets chosen as your argument list maps its parameters.
in your code val person1 = Person("Joe", 25) your are calling a constructor wich have two parameters and thats the first constructor not the second.
call the second constructor like that val person1 = Person("Joe", 25,"name").
i hope that was clear.

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

In which situation val/var is necessary in Kotlin constructor parameter?

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.

Categories

Resources