I am trying to create an ArrayList in a class, like so:
class ConvertableTests : BaseTest(){
var categories = ArrayList<String>()
categories.add('a') <---- //Expecting member declaration error here
inner class ConvertableClass : Convertible...
Why I can't add objects to my array list after I initialize the list?
You can add items into the list after you initialize the list if you aren't doing so at the root scope of the class. Same as if you would have tried to do the same thing in Java.
i.e.
//this won't work, like you just found out
class Example {
var categories = ArrayList<String>()
categories.add("a") // this isn't inside a function or an `init` block
}
You need to put it inside of a function or an init block
fun functionExample() {
var categories = ArrayList<String>()
categories.add("a") // This would work fine
}
or
class Example {
var categories = ArrayList<String>()
init {
categories.add("a")
}
}
To elaborate on Sergey's example of the apply and why that works if you don't do it inside of a function or an init
class Example {
var categories = ArrayList<String>().apply {
add("a")
}
}
The kotlin compiler is performing an optimization and it's actually treating this as if you were putting it into an init block. If you decompile this and see what's happening, it's actually doing this
/// This is what it compiles back up to in Java
public Example() {
ArrayList var8 = new ArrayList();
var8.add("a");
this.category = var8;
}
Which is the same thing that happens when you use the init block.
Hope that helps!
You can use init block to initialize array:
class ConvertableTests : BaseTest() {
var categories = ArrayList<String>()
init {
categories.add("a")
}
// ...
}
Or apply extension function:
var categories = ArrayList<String>().apply {
add("a")
}
Also you should use double quotes " to add a String:
var categories = ArrayList<String>()
categories.add("a")
Single quotes are used for Chars:
var categories = ArrayList<Char>()
categories.add('a')
Related
I have a question in List<Contact>() I'm asked to pass init and size. I'm not sure if it's obligated to pass it as in my following tutorial ArrayList<String>() was empty, maybe it's because I was using List<>? Also, it doesn't recognize lowercase() and add() is it also related to List<>?
Code Snippet
val contacts = remember { DataProvider.contactList }
var filteredContacts: List<Contact>
val textState = remember { mutableStateOf(TextFieldValue("")) }
LazyColumn(
...
) {
val searchText = textVal.value.text
filteredContacts = if (searchText.isEmpty()){
contacts
}
else{
val resultList = List<Contact>()
for (contact in contacts) {
if (contact.lowercase(Locale.getDefault()).contains(searchText.lowercase(Locale.getDefault()))) {
resultList.add(contact)
}
}
resultList
}
In kotlin, List has no add method. For that you would need to have a MutableList.
Regarding lowercase method, this is available for Strings. You are trying to apply that to a Contact object, which I guess has no lowercase method.
I have this code using Kotlin:
class A{
var myVariable:String?=null
constructor(myVariable:String){
this.myVariable = myVariable
}
init {
println("Success !")
}
inner class B{
init {
println(myVariable)
}
}
}
fun main(args:Array<String>){
var b = A("test").B // this does not work
}
And unfortunately it does not work I get:
Error:(20, 23) Kotlin: Nested class 'B' accessed via instance reference
Error:(20, 23) Kotlin: Classifier 'B' does not have a companion object, and thus must be initialized here
How can I solve my problem?
When you do:
A("test").B
You're saying "Fetch something from an instance of A" - in this case, it's a class. However, this isn't the syntax you're looking for in your case. You can get mostly anything, but getting a reference is a separate issue. If you want to get a function, the syntax is different from getting a field or calling a function. Although this isn't very important, bit might still be worth keeping that in mind.
Since B is an inner class, you're so far entirely correct that you need an instance of A first. But you also need an instance of B. When you initialize B, it's still "connected" to the parent class, which is why you can access outer variables without any problems. However, it's still an initializable class - and you need to initialize it.
So you need to initialize B as well. The Kotlin syntax for this is pretty nice (where as the syntax in Java is slightly horrible) - all you need to add is () at the end.
So you'll end up with this:
val b = A("test").B()
// ...
This is because it's an inner class. If you had a static inner class (in Kotlin, that's a class within a class without the inner keyword), the initialization would've been A.B() - A isn't initialized in those cases.
You can also split up the initialization:
val a = A("test")
val b = a.B();
Once you have the variable, it's exactly like every other variable - the only difference here is the initialization.
Try this:
class A{
var myVariable:String?=null
constructor(myVariable:String){
this.myVariable = myVariable
}
init {
println("Success !")
}
inner class B{
init {
println(myVariable)
}
}
}
fun main(args:Array<String>){
var b = A("test").B() // You have to call the constructor here
}
You should create an instance (call constructor) of class B before accessing its members:
fun main(args:Array<String>) {
val b = A("test").B()
b.someFunction()
}
class A {
var myVariable:String? = null
constructor(myVariable: String) {
this.myVariable = myVariable
}
init {
println("Success !")
}
inner class B {
init {
println(myVariable)
}
fun someFunction() {
myVariable = "set new value to the variable"
}
}
}
Let you have some variable and apply, run, let, also, takeIf or with function:
// private lateinit var someAdapter: SomeAdapter
recycler_view.apply {
this.layoutManager = LinearLayoutManager(context)
if (this::someAdapter.isInitialized) { // Compilation error.
this.adapter = someAdapter
}
}
How to access a value or state of someAdapter?
You can use one of the following.
recycler_view.apply {
this.layoutManager = LinearLayoutManager(context)
if (this#OuterClass::someAdapter.isInitialized) { //qualified
this.adapter = someAdapter
}
}
Or
recycler_view.apply {
this.layoutManager = LinearLayoutManager(context)
if (::someAdapter.isInitialized) { // qualified works for immediate outer scope
this.adapter = someAdapter
}
}
You can access it via this#YourClass.adapter. It's called qualified this, you can have a look at the documentation here
Not direct answer, but rather design opinion: lateinit vars are supposed to be used when you're guaranteed to have them set before use.
isInitialized was not even present before Kotlin 1.2, it was only added (opinion ahead) as an error fallback.
If you're getting notInitializedException thats good indicator you're not properly initializing the field, if you explicitly initialize it later then you should use nullable field instead: SomeAdapter?.
Accessing the outer this is possible via this#OuterClass. But, if you do not have any other someAdapter you can also just omit the this#YourOuterClass and simply use the following instead:
if (::someAdapter.isInitialized) {
So given the following, it is clear that someVar of Outer is meant:
class Outer<T> where T : Any {
lateinit var someVar : T
inner class Inner {
fun isItInitialized() = ::someVar.isInitialized
}
}
Given the following however:
class Outer<T> where T : Any {
lateinit var someVar : T
inner class Inner {
lateinit var someVar : T
fun isItInitialized() = ::someVar.isInitialized // now someVar of Inner is used
}
}
you need to specify this#Outer::someVar.isInitialized if you want to access the outer someVar.
I'm trying to assign a callback implementation of an interface (defined inside a class A) to a variabile defined inside another class B. Let's say that class A has the interface OnSomethingHappens which defines a doSomething method.
Inside class B I've defined my callback variable like this:
private lateinit var callback:A.OnSomethingHappens
I need to create an instance of class A passing callback variabile to the constructor in this way:
myinstanceA = A(callback)
I'm trying to assign an instance of an anonymous class that implements A.OnSomethingHappens using this code:
callback = object : A.OnSomethingHappens {
override fun doSomething(..){
//here I put the implementation of this method
}
}
but the compiler says "expecting member declaration" for my callback variable and "name expected" for object.
What I'm doing wrong?
Instead, I'm able to define and at the same time assign the callback variable in this way:
private var callback = object : A.OnSomethingHappens {
override fun doSomething(..){
//here I put the implementation of this method
}
}
Why? Which are the differences and a possible solution?
I'm trying to assign an instance of an anonymous class that implements A.OnSomethingHappens using this code: ...
This should work, but only inside a method:
class B {
private lateinit var callback:A.OnSomethingHappens
fun someMethod() {
callback = object : A.OnSomethingHappens { ... }
}
...
}
Given the error message and that private var compiles (which doesn't inside a method), you are trying to set it directly in the body of the class instead:
class B {
private lateinit var callback:A.OnSomethingHappens
callback = object : A.OnSomethingHappens { ... }
...
}
This is illegal: the only code you can write there is member definitions and init blocks.
Also, if you can initialize callback directly where it's defined or inside init, there's no point to lateinit in the first place.
It's not obvious from the code snippets cut down to such small pieces, but your issue is that you're writing down the assignment inside the body of a class, but not inside a function.
Here's an example of a valid declaration and immediate assignment:
class A {
var x: X? = X()
}
Here's an example of an invalid assignment, which places an arbitrary expression in the body of a class:
class A {
lateinit var x: X
x = X() // expression placed inside the class body, invalid syntax
someFunction() // extra example, calling functions here is invalid in the same way
}
Instead, you could put this initialization inside a function:
class A {
lateinit var x: X
fun initializeX() {
x = X()
}
}
Or inside an initializer block (in this case, you don't even need lateinit):
class A {
var x: X
init {
x = X()
}
}
While I couldn't explain how to solve your exact problem, because I can't quite understand what code is in which class, I hope these examples and explanation helped.
Hmm, let me propose a variant. It's more simple for me:
import android.util.Log
class SomeClass {
fun mainMethod() {
ClassWithCallback(
{ myBackValue: String ->
logMyString(myBackValue)
}
)
//simplify
ClassWithCallback({ logMyString(it) })
}
private fun logMyString(myBackValue: String) {
Log.d("SomeClass", myBackValue)
}
}
class ClassWithCallback(private val myCallBack: (myBackValue: String) -> Unit) {
init {
// we do something here and back it by callback
val myString = "Hello! Pass me back!"
myCallBack.invoke(myString.toUpperCase())
}
}
Using Kotlin lambdas. Hope this will help you.
I have been reading about properties in Kotlin, including custom getters and setters.
However, I was wondering if it is possible to create a custom getter with extra parameters.
For example, consider the following method in Java:
public String getDisplayedValue(Context context) {
if (PrefUtils.useImperialUnits(context)) {
// return stuff
} else {
// return other stuff
}
}
Note that the static method in PrefUtils has to have Context as a parameter, so removing this is not an option.
I would like to write it like this in Kotlin:
val displayedValue: String
get(context: Context) {
return if (PrefUtils.useImperialUnits(context)) {
// stuff
} else {
// other stuff
}
}
But my IDE highlights all of this in red.
I am aware I can create a function in my class to get the displayed value, but this would mean I would have to use .getDisplayedValue(Context) in Kotlin as well instead of being able to refer to the property by name as in .displayedValue.
Is there a way to create a custom getter like this?
EDIT: If not, would it be best to write a function for this, or to pass Context into the parameters of the class constructor?
As far as I know, property getter cannot have parameter. Write a function instead.
You can do this by having a property that returns an intermediate object that has a get and/or set operator with the parameters that you want, rather than returning the value directly.
Having that intermediate object be an inner class instance may be useful for providing easy access to the parent object. However, in an interface you can't use inner classes so in that case you might need to provide an explicit constructor parameter referencing the parent object when constructing your intermediate object.
For instance:
class MyClass {
inner class Foo {
operator fun get(context: Context): String {
return if (PrefUtils.useImperialUnits(context)) {
// return stuff
} else {
// return other stuff
}
}
}
val displayedValue = Foo()
}
...
val context : Context = whatever
val mc : MyClass = whatever
val y: String = mc.displayedValue[context]
You can do for example:
val displayedValue: String by lazy {
val newString = context.getString(R.string.someString)
newString
}