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

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

Related

How To Return Nested Variable?

I don't know how to RETURN variable from the following function.
Here is the code...
downloadData.setOnClickListener {
val handler = Handler(Looper.getMainLooper())
handler.post {
val fetchData =
FetchData("http://localhost/xampp/CRM/PHP/show_contacts_db.php")
if (fetchData.startFetch()) {
if (fetchData.onComplete()) {
val result = fetchData.data.toString()
Log.i("FetchData", result)
val companyName = result.substringAfter("Name: ").substringBefore(";")
showContactName.text = "${companyName}"
val companyNumber = result.substringAfter("Number: ").substringBefore(";")
showContactNumber.text = "${companyNumber}"
}
}
}
}
companyName and companyNumber needed to be returned so I can use it in other places.
When I Try to use Return companyNumber I have a message that "return" is not allowed here.
Generally with lambdas, you don't explicitly return a value - the lambda returns the value of the last expression. Using your code as an example (it won't actually work but we'll get to that!):
handler.post {
...
companyNumber
}
which is the same as how things like map calls take a transformation function
listOf(1, 2, 3).map { it * 2 }
that's just doubling each number, but the result is being implicitly returned and stored in the resulting list, right? And it lets you chain lambdas together, since each one evaluates to a value (which might be Unit if it "doesn't return a result")
If you want, you can explicitly use what's called a qualified return:
handler.post {
...
return#post companyNumber
}
where you're naming the function call you're returning to.
Kotlin docs: returning a value from a lambda expression
Also if you want to return two values, you can't do that - so you'll have to bundle them up in a single object. You could just return a Pair, or create a data class that's more readable:
return#post Pair(companyName, companyNumber)
//or
data class CompanyDeets(val name: String, val number: String)
...
return#post CompanyDeets(companyName, companyNumber)
But aside from how you do it in general, why do you want to return anything here? Handler#post takes a Runnable which returns nothing (void in Java), and View.OnClickListener#onClick doesn't return anything either.
Neither of them would do anything with a value you returned - and if you explicitly return a value, that means your lambda's signature doesn't match (right now it's implicitly returning Unit to match what's expected by the caller), and you'll get an error
What you probably want to do instead, is create a function inside your class (Activity or whatever) that uses your data, something like fun doSomethingWith(companyName: String, companyNumber: String) and call that inside your lambda. That's way you're executing code in reaction to a click
just declare var Company Name in global, or create a function with that params
var companyName: String? = null
handler.post {
...
companyName = result.substringAfter("Name: ").substringBefore(";")
}
OR
handler.post {
...
save(result.substringAfter("Name: ").substringBefore(";"))
}
fun save(companyName: String){ ... }

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

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

Kotlin - How to decide between "lateinit" and "nullable variable"?

I am confuse for lateinit and nullable variable, which one to use for variable.
lateinit var c: String
var d: String? = null
c = "UserDefinedTarget"
// if not added initialisation for c than throws UninitializedPropertyAccessException
if (c == "UserDefinedTarget") {
//do some stuff.
}
//not throws any exception whether d is initialise or not.
if(d == "UserDefinedTarget") {
//do some stuff
}
A type that is nullable is just that, a thing that has a valid state that is null.
A non-nullable late init var represents something where null is an invalid state, but for some reason you can't populate it in the constructor.
Android Activities are a good example of a use of lateinit. Activities must have a no args constructor and their lifecycle only really starts with onCreate().
These are two completely different concepts.
You can use lateinit to avoid null checks when referencing the property. It's very convenient in case your properties are initialized through dependency injection, or, for example, in the setup method of a unit test.
However, you should keep in mind that accessing a lateinit property before it has been initialized throws an exception. That means you should use them only if you are absolutely sure, they will be initialized.
Nullable types, on the other hand, are used when a variable can hold null.
class A {
lateinit var a: String
fun cat() {
print(a.length) // UninitializedPropertyAccessException is thrown
a = "cat"
print(a.length) // >>> 3
}
}
class B {
var b: String? = null
fun dog() {
print(b.length) // won't compile, null check is obligatory here
print(b?.length) // >>> null
b = "dog"
print(b?.length) // >>> 3
}
}
For more information:
Late-initialized properties
Nullable types
It depends.
Nullable variable means that variable can hold value or null. lateinit means that variable must be initialised later. It should be initialized before accessing it. If you attempt accessing uninitialized lateinit variable UninitializedPropertyAccessException will be thrown.
It's always better to avoid using nulls in your app. Nulls are evil. So if you can initialize variable in onCreate then it's better to use lateinit. Also if you use dependency injection in your app and fields should be injected it's also a valid case to use lateinit instead of handling nulls.
If for some reason you can't initialize variable, initializing code can result to null, or null can be assigned to this variable later than you should use nullable variable. Generally speaking if null is a valid value for the variable.
Use lateinit for properties that cannot be initialized in a constructor.

Unresolved reference inside anonymous Kotlin listener

I have the code below. It is Kotlin. Any idea why textToSpeech from textToSpeech.setLanguage(Locale.UK) is telling that there is no reference resolved for textToSpeech?
val textToSpeech = TextToSpeech(
applicationContext,
object : TextToSpeech.OnInitListener {
override fun onInit(status: Int) {
if (status == TextToSpeech.SUCCESS) {
textToSpeech.setLanguage(Locale.UK)
}
}
})
At first I assumed it is an Idea kotlin plugin bug, but it seems that it actually can't be compiled
Kotlin has hardened the variables initialization policy, and it's now prohibited to reference the variable inside its initializer, even in lambdas and object expressions, which seems reasonable: imagine that a lambda is called immediately before the variable assignment.
For your case, I can suggest as a workaround using an object expression in this quite cumbersome construct:
val textToSpeech = object {
val value: TextToSpeech get() = inner
private val inner = TextToSpeech(
applicationContext,
{ value.setLanguage(Locale.UK) }
)
}.value
This will initialize an anonymous object with inner inside that is acceptable through value property. Note that the inner initializer uses value property. Then the value is extracted and can be used.
But please keep in mind that this trick is unsafe: in runtime, using value before inner is assigned (e.g. in TextToSpeech constructor) will throw NullPointerException.
Also, I've replaced the OnInitListener with a lambda using SAM conversion to be short, but object expression can still be used there.
UPD: check this question for my effort to generalize this approach. Using it, you can write
val textToSpeech = selfReference {
TextToSpeech(
applicationContext,
{ self.setLanguage(Locale.UK) }
)
}
See the sources on Github.
This is a very readable and clear way to face that problem. First you should define this:
fun <T> selfReferenced(initializer: () -> T) = initializer.invoke()
operator fun<T> T.getValue(any: Any?, property: KProperty<*>) = this
and later use
val valueName: ValueType by selfReferenced{
//here you can create and use the valueName object
}
Using your problem as example you can do:
val textToSpeech:TextToSpeech by selfReferenced {
TextToSpeech(
applicationContext,
TextToSpeech.OnInitListener { status ->
if (status == TextToSpeech.SUCCESS) {
textToSpeech.setLanguage(Locale.UK)
}
})
}
Inside the selfReferenced block you can use the outer object with no restrictions. The only thing you should take care of, is declaring the type explicitly to avoid recursive type checking issues.

Categories

Resources