property getter or setter expected - android

I want to use a bitmap var in a class. It makes 'property getter or setter expected' error. What is the problem?
The error shows around 'bmp? : Bitmap = null'.
How can I solve the problem?
And I don't understand why I must use getter or setter for private properties in a class.
class MyView(context: Context?) : View(context) {
private var bmp? : Bitmap = null
init {
bmp = BitmapFactory.decodeResource(resources, R.mipmap.ic_launcher)
}
override fun onDraw(canvas: Canvas?) {
super.onDraw(canvas)
canvas?.drawColor(Color.BLUE)
canvas?.drawBitmap(bmp,10f,10f, null)
}
}

Issue is that you're going to create Nullable object using safe call operator, but your syntax is wrong. Inspite of placing ? at variable, you'll need to put it at Reference type.
Check correct syntax :
private var bmp : Bitmap? = null
And then you can access this variable with safe call operator like below :
bmp?.someMethodCall() // This line will never throw you null pointer exception because of ? (Safe call operator)
Check out more here.

Please try below line
lateinit var bmp : Bitmap

Related

Getting error "Smart cast to 'EditText!' is impossible, because 'usernameET' is a mutable property that could have been changed by this time" [duplicate]

And the Kotlin newbie asks, "why won't the following code compile?":
var left: Node? = null
fun show() {
if (left != null) {
queue.add(left) // ERROR HERE
}
}
Smart cast to 'Node' is impossible, because 'left' is a mutable
property that could have been changed by this time
I get that left is mutable variable, but I'm explicitly checking left != null and left is of type Node so why can't it be smart-casted to that type?
How can I fix this elegantly?
Between execution of left != null and queue.add(left) another thread could have changed the value of left to null.
To work around this you have several options. Here are some:
Use a local variable with smart cast:
val node = left
if (node != null) {
queue.add(node)
}
Use a safe call such as one of the following:
left?.let { node -> queue.add(node) }
left?.let { queue.add(it) }
left?.let(queue::add)
Use the Elvis operator with return to return early from the enclosing function:
queue.add(left ?: return)
Note that break and continue can be used similarly for checks within loops.
1) Also you can use lateinit If you are sure you will do your initialization later on onCreate() or elsewhere.
Use this
lateinit var left: Node
Instead of this
var left: Node? = null
2) And there is other way that use !! end of variable when you use it like this
queue.add(left!!) // add !!
There is a fourth option in addition to the ones in mfulton26's answer.
By using the ?. operator it is possible to call methods as well as fields without dealing with let or using local variables.
Some code for context:
var factory: ServerSocketFactory = SSLServerSocketFactory.getDefault();
socket = factory.createServerSocket(port)
socket.close()//smartcast impossible
socket?.close()//Smartcast possible. And works when called
It works with methods, fields and all the other things I tried to get it to work.
So in order to solve the issue, instead of having to use manual casts or using local variables, you can use ?. to call the methods.
For reference, this was tested in Kotlin 1.1.4-3, but also tested in 1.1.51 and 1.1.60. There's no guarantee it works on other versions, it could be a new feature.
Using the ?. operator can't be used in your case since it's a passed variable that's the problem. The Elvis operator can be used as an alternative, and it's probably the one that requires the least amount of code. Instead of using continue though, return could also be used.
Using manual casting could also be an option, but this isn't null safe:
queue.add(left as Node);
Meaning if left has changed on a different thread, the program will crash.
The practical reason why this doesn't work is not related to threads. The point is that node.left is effectively translated into node.getLeft().
This property getter might be defined as:
val left get() = if (Math.random() < 0.5) null else leftPtr
Therefore two calls might not return the same result.
Change var left: Node? = null to lateinit var left: Node. Problem solved.
Your most elegant solution must be:
var left: Node? = null
fun show() {
left?.also {
queue.add( it )
}
}
Then you don't have to define a new and unnecessary local variable, and you don't have any new assertions or casts (which are not DRY). Other scope functions could also work so choose your favourite.
Do this:
var left: Node? = null
fun show() {
val left = left
if (left != null) {
queue.add(left) // safe cast succeeds
}
}
Which seems to be the first option provided by the accepted answer, but that's what you're looking for.
For there to be a Smart Cast of the properties, the data type of the property must be the class that contains the method or behavior that you want to access and NOT that the property is of the type of the super class.
e.g on Android
Be:
class MyVM : ViewModel() {
fun onClick() {}
}
Solution:
From: private lateinit var viewModel: ViewModel
To: private lateinit var viewModel: MyVM
Usage:
viewModel = ViewModelProvider(this)[MyVM::class.java]
viewModel.onClick {}
GL
Try using the not-null assertion operator...
queue.add(left!!)
How I would write it:
var left: Node? = null
fun show() {
val left = left ?: return
queue.add(left) // no error because we return if it is null
}
Perform as below :-
var left: Node? = null
Use a null safe call
left?.let { node -> queue.add(node) } // The most preferred one
This worked for me:
private lateinit var varName: String

How do I initialize a collection value for a MutableLiveData object?

class Foo : ViewModel() {
val bars: MutableLiveData<ArrayList<Bar>> = MutableLiveData()
get() {
if(field.value == null) {
field.setValue(ArrayList()) // NullPointerException
}
}
}
class FooTest(){
#Test fun itShouldNotBlowUp() {
Foo() //nullPointerException
}
}
I don't understand how to initialize the value of a MutableLiveData object. I've tried to lazily initialize it via the getter and with an init block. Both approaches throw a null pointer when setting the value. bars is not null however.
Here is the stacktrace:
java.lang.NullPointerException
at android.arch.core.executor.DefaultTaskExecutor.isMainThread(DefaultTaskExecutor.java:58)
at android.arch.core.executor.ArchTaskExecutor.isMainThread(ArchTaskExecutor.java:116)
at android.arch.lifecycle.LiveData.assertMainThread(LiveData.java:434)
at android.arch.lifecycle.LiveData.setValue(LiveData.java:279)
at android.arch.lifecycle.MutableLiveData.setValue(MutableLiveData.java:33)
at org.Foo.<init>(Foo.kt:10)
at org.FooTest.ShouldNotBlowUp(FooTest.kt:3)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
How do I initialize the ArrayList and set it as the value of bars?
Maybe the reason is that you are trying to run this in the test. Your sample fails in DefaultTaskExecutor.isMainThread(), that looks like this:
public boolean isMainThread() {
return Looper.getMainLooper().getThread() == Thread.currentThread();
}
So Looper.getMainLooper() returns null in the test environment.
And also, have you tried to initialize property via 'lazy' delegate?
val bars: MutableLiveData<List<Bar>> by lazy {
MutableLiveData<List<Bar>>().apply {
value = emptyList()
}
}
That works fine in my case and feels more idiomatic
The answer to the question is: if you want to give it an empty value clearly, but the variable is not null and you can at least use it without breaking the program.
to create a variable:
val myVariable = MutableLiveData<ArrayList<String>>()
Well, now you only have to pass the constructor of the empty list within the type parentheses so that your variable does not remain with a Null value.
val myVariable = MutableLiveData<ArrayList<String>>(arrayListOf())
I know it's an old question but in case it can help someone, it helped me discover this ;)

How to "lock" static object in Kotlin

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

Kotlin property with getter. Can I not specify an initial value?

I want to create a singleton class, but unfortunately, Android needs Context for almost anything so I need it to create an instance. So I just assumed the user called init(), and then return the instance. As you see below, if the _instance is null, an exception will be thrown, so the get method cannot return null.
But Kotlin says I must initialise instance. The things is, that MyClass cannot be created without a context. So I would like not to specify an initial value. How can I do that?
companion object
{
protected var _instance:MyClass? = null;
fun init(context:Context)
{
_instance = MyClass(context)
}
var instance:MyClass //<---This causes a compile error.
get()
{
if(_instance==null) throw RuntimeException("Call init() first.");
return _instance!!;
}
}
Change the var to val and it should work:
....
val instance: MyClass
....
A variable property (var) not only assumes a getter, but also a setter. Since you provided no setter, a default one was generated set(value) { field = value }. Despite is uselessness in this situation, the default setter uses field, thus requires its initialization.
Use lateinit property
public class MyTest {
lateinit var subject: TestSubject
fun setup() {
subject = TestSubject()
}
fun test() {
subject.method()
}
}

why Smart cast error occur in kotlin? [duplicate]

And the Kotlin newbie asks, "why won't the following code compile?":
var left: Node? = null
fun show() {
if (left != null) {
queue.add(left) // ERROR HERE
}
}
Smart cast to 'Node' is impossible, because 'left' is a mutable
property that could have been changed by this time
I get that left is mutable variable, but I'm explicitly checking left != null and left is of type Node so why can't it be smart-casted to that type?
How can I fix this elegantly?
Between execution of left != null and queue.add(left) another thread could have changed the value of left to null.
To work around this you have several options. Here are some:
Use a local variable with smart cast:
val node = left
if (node != null) {
queue.add(node)
}
Use a safe call such as one of the following:
left?.let { node -> queue.add(node) }
left?.let { queue.add(it) }
left?.let(queue::add)
Use the Elvis operator with return to return early from the enclosing function:
queue.add(left ?: return)
Note that break and continue can be used similarly for checks within loops.
1) Also you can use lateinit If you are sure you will do your initialization later on onCreate() or elsewhere.
Use this
lateinit var left: Node
Instead of this
var left: Node? = null
2) And there is other way that use !! end of variable when you use it like this
queue.add(left!!) // add !!
There is a fourth option in addition to the ones in mfulton26's answer.
By using the ?. operator it is possible to call methods as well as fields without dealing with let or using local variables.
Some code for context:
var factory: ServerSocketFactory = SSLServerSocketFactory.getDefault();
socket = factory.createServerSocket(port)
socket.close()//smartcast impossible
socket?.close()//Smartcast possible. And works when called
It works with methods, fields and all the other things I tried to get it to work.
So in order to solve the issue, instead of having to use manual casts or using local variables, you can use ?. to call the methods.
For reference, this was tested in Kotlin 1.1.4-3, but also tested in 1.1.51 and 1.1.60. There's no guarantee it works on other versions, it could be a new feature.
Using the ?. operator can't be used in your case since it's a passed variable that's the problem. The Elvis operator can be used as an alternative, and it's probably the one that requires the least amount of code. Instead of using continue though, return could also be used.
Using manual casting could also be an option, but this isn't null safe:
queue.add(left as Node);
Meaning if left has changed on a different thread, the program will crash.
The practical reason why this doesn't work is not related to threads. The point is that node.left is effectively translated into node.getLeft().
This property getter might be defined as:
val left get() = if (Math.random() < 0.5) null else leftPtr
Therefore two calls might not return the same result.
Change var left: Node? = null to lateinit var left: Node. Problem solved.
Your most elegant solution must be:
var left: Node? = null
fun show() {
left?.also {
queue.add( it )
}
}
Then you don't have to define a new and unnecessary local variable, and you don't have any new assertions or casts (which are not DRY). Other scope functions could also work so choose your favourite.
Do this:
var left: Node? = null
fun show() {
val left = left
if (left != null) {
queue.add(left) // safe cast succeeds
}
}
Which seems to be the first option provided by the accepted answer, but that's what you're looking for.
For there to be a Smart Cast of the properties, the data type of the property must be the class that contains the method or behavior that you want to access and NOT that the property is of the type of the super class.
e.g on Android
Be:
class MyVM : ViewModel() {
fun onClick() {}
}
Solution:
From: private lateinit var viewModel: ViewModel
To: private lateinit var viewModel: MyVM
Usage:
viewModel = ViewModelProvider(this)[MyVM::class.java]
viewModel.onClick {}
GL
Try using the not-null assertion operator...
queue.add(left!!)
How I would write it:
var left: Node? = null
fun show() {
val left = left ?: return
queue.add(left) // no error because we return if it is null
}
Perform as below :-
var left: Node? = null
Use a null safe call
left?.let { node -> queue.add(node) } // The most preferred one
This worked for me:
private lateinit var varName: String

Categories

Resources