var booleanresult : MutableLiveData<Boolean>? = null
fun checksubcat() = viewModelScope.launch(Dispatchers.IO) {
val trueorfalse : Boolean = productsDao.getSubCatId(subcat_id)
booleanresult?.value = trueorfalse
Log.e("update","view model"+booleanresult?.value.toString())
}
Log value for trueorfalse variable :
2022-09-18 06:58:32.305 11820-11849/com.store.pasumainew E/update: trueorfalse : false
I got log value of null for booleanresult:
2022-09-18 06:58:32.305 11820-11849/com.store.pasumainew E/update: booleanresult : null
I need booleanresult as MutableLiveData ..how to set trueorfalse value to MutableLiveData
Your LiveData property should not be nullable and should never be null. And it should not even be a var because there should never be a reason to create a new one instead of setting the value of the existing instance.
Declare it as non-nullable (no question mark), give it an initial value, and make it a val.
val booleanResult = MutableLiveData<Boolean>()
You also can’t directly set the value using Dispatchers.IO. Convention is to usually not change the dispatcher for your launch call but only use it for specific sections of your coroutine using withContext. But if for some reason you didn’t follow the convention, then you need to use postValue() instead of value =, since that is only allowed to be done on the main thread.
Related
In Kotlin, as I know, you can call a view in two ways:
Declaring a variable
val btn: Button = btnLogin
btn.text = "newLogin"
Using it directly
btnLogin.text= "newLogin"
So what are the differences between these implementations?
I know that declaring a variable may be more useful when calling repeatedly and may prevent typos, but what are the advantages?
Assuming btnLogin is a nullable property, then declaring a local variable allows you to acquire a non-null reference after checking for null. For example:
private var btnLogin: Button? = null
override fun onViewCreated(view: View) {
btnLogin = view.findViewById(R.id.my_button)
}
private fun otherMethod() {
val loginButton = btnLogin
if (loginButton != null) {
loginButton.doX()
loginButton.doY()
loginButton.doZ()
}
}
Since the property can be changed from non-null to null at any time, capturing the current value to a local variable allows you to capture a fixed value at the point where it's declared. Kotlin does have many other constructs you can use instead of capturing a local variable, however. For example, this would be equivalent:
btnLogin?.let { loginButton ->
loginButton.doX()
loginButton.doY()
loginButton.doZ()
}
In general, capturing a local variable just ensures that the same value is referenced throughout, but in most cases, it's likely not necessary.
I need to know if this line code is right, my teacher told me it's correct, but I disagree 'cause "lateinit" can't be with a variable that could be null or not.
Line code:
lateinit var text : String?
Code:
val cadena = null
lateinit var text : String?
text = null
text = cadena ?: "Hola"
text?.let { println(text) }
You are correct and your teacher is wrong. Proof: lateinit var text : String? results in compilation error with Kotlin 1.3.50:
'lateinit' modifier is not allowed on properties of nullable types
How any teacher can possibly claim such code is correct is beyond me...
I would like to add a little deep dive into lateinit properties in Kotlin.
'lateinit' modifier is not allowed on properties of nullable type - this can be found in Kotlin documentation. This kind of modifier is for special kind of constructions. It's for fields that will be initialized somewhen after object creation. For example, via DI framework or mocking framework.
But, what is under that field? If we would check it, we will simply find that before initialization property has null value. Nothing more, nothing less, just null. But, if we would like to access that property before initialization UninitializedPropertyAccessException is thrown.
In Kotlin 1.3 lateinit properties got new property - isInitialized (to use it: ::lateinitiProperty.isInitilized). So, before we access that property we are able to check if under that field is null or something else, without throwing exception.
But, lateinit means that object will be initialized later as not null property. And a programmer guarantee that this value is not null after intialization. If it could be, why just not use nullable type?
If there is a way to uninialize lateinit property? Yes, it is. Via reflection we can set that value to null again (JVM is not null-safe). And accessing that field will not finish with NPE execption, but with UninitializedPropertyAccessException. And .isInitialized will return false for field that refers to null.
And how does it work?
class MyClass {
lateinit var lateinitObject: Any
fun test() {
println("Is initialized: ${::lateinitObject.isInitialized}") // false
lateinitObject = Unit
println("Is initialized: ${::lateinitObject.isInitialized}") // true
resetField(this, "lateinitObject")
println("Is initialized: ${::lateinitObject.isInitialized}") // false again
lateinitObject // this will throw UninitializedPropertyAccessException
}
}
fun resetField(target: Any, fieldName: String) {
val field = target.javaClass.getDeclaredField(fieldName)
with (field) {
isAccessible = true
set(target, null)
}
}
Ofc, using lateinit that way is probably not what you want, and treat is as a curio about lateinit design in JVM.
And due to your teacher - he wasn't right. Even if lateinit may refer to null (and it does actually), you cannot declare it as a nullable type. If you need to, you don't need lateinit modifier.
I am new to kotlin.
I am reading a key and value from properties file, in a kotlin program. But I don't know how to directly return the value of a key.
Please find the application.yml and abc.class(this is a kotlin class) below.
application.yml
abcconfig:
isabcEnabled:
default: false
xyz: true
def: true
abc.class
import org.springframework.boot.context.properties.ConfigurationProperties
import org.springframework.stereotype.Component
#Component
#ConfigurationProperties(prefix = "abcconfig")
class AbcConfig {
private var abcEnabled: Map<String, Boolean> = mutableMapOf()
fun getabcEnabledValue(siteId: String?): Boolean {
val abc: Boolean
val key: String? = if (abcEnabled.containsKey(key)) key else "default"
abc = abcEnabled[key]
return abc
}
fun setAbcEnabled(abcEnabled: Map<String, Boolean>) {
this.abcEnabled = abcEnabled
}
}
This is about nullability. The Kotlin compiler keeps track of whether each value could be null or not, and prevents you from doing things that would be unsafe.
The code in this question has one particular nullability issue. (It also has some confusion, including two references to key before it's set. I'll assume those should be siteId.)
The issue is what happens when the abcEnabled map doesn't contain the requested key. If the key is present, then the […] operator will return the corresponding Boolean value; but if the key is not present (which could happen if the map doesn't contain a "default" key), it returns null. However, the variable you're trying to assign it to is of type Boolean, which doesn't allow nulls. That's why the compiler complains.
So you'll have to decide what you want to happen if the map contains no "default" key. (Or find a way to ensure it always does; but that's a lot harder, especially if the method could be called before the object is fully initialised, or while another thread is setting or updating the map. So it's much safer to handle the case gracefully.)
If you want to return false in that case, the code could boil down to:
fun getabcEnabledValue(siteId: String?): Boolean {
val key: String? = if (abcEnabled.containsKey(siteId)) siteId else "default"
return abcEnabled[key] ?: false
}
or even (for better thread-safety as well as brevity and clarity):
fun getabcEnabledValue(siteId: String?)
= abcEnabled[siteId] ?: abcEnabled["default"] ?: false
Or if you want to return null in that case, simply declare the function as returning Boolean? (which allows null) — or leave off the ?: false in the last example.
(Also, as a matter of style, I'm not sure why you've made abcEnabled a private property and then added your own setter. Is it really necessary to hide the getter? If not, a public property would be simpler. And it's probably worth making the capitalisation of abc in the method names consistent.)
I looking for a way to have default values take the place of nulls when passed as arguments. My motivation is purely to reduce the amount of code written (I want to avoid having overloaded functions/constructors or manual 'if null' checks)
My use case is within a Spring RestController, I want default values of a method called by the controller to be used without needing to state those default values outside the function.
I thought perhaps that using named parameters might provide this functionality but my experiments show otherwise. Perhaps there is a way with the elvis operator?
Example Code:
fun someFunction(first: Long = 1, second: Int = 2 ) {
// Do something
}
#GetMapping
fun someEndpoint(#RequestParam("first") firstParam: Long?):ResponseEntity<Any> {
someFunction(firstParam) // Attempt 1: "Required: Long\n Found: Long?
someFunction(first = firstParam) // Attempt 2: Same error
}
Hopefully you can help
There aren't any specific language features that would do this for you, the default argument mechanism isn't connected to nullability in any way.
However, you can achieve this in a more manual fashion by making your parameters nullable, and immediately substituting default values inside the function if they're null:
fun someFunction(first: Long? = null, second: Int? = null) {
val actualFirst: Long = first ?: 1
val actualSecond: Int = second ?: 2
// Do something with actualFirst and actualSecond
}
The #RequestParam annotation has a default value option named "defaultValue".
you can use it like so:
#GetMapping
fun someEndpoint(#RequestParam(name = "first", defaultValue = "1") firstParam: Long):ResponseEntity<Any> {
someFunction(firstParam) // firstParam equals to 1 if null was passed to the endpoint
}
Just ver confused about casting and how to set up class variables. In java it was possible to do
private var mSectionsStatePageAdapter : SectionsStatePagerAdapter? = null
private val mViewPager : ViewPager? = null
now we're in kotlin
class MainActivity : AppCompatActivity() {
private var mSectionsStatePageAdapter : SectionsStatePagerAdapter? = null
private val mViewPager : ViewPager? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val mytoolbar:Toolbar = findViewById(R.id.top_toolbar)
setSupportActionBar(mytoolbar)
mSectionsStatePageAdapter = SectionsStatePagerAdapter(getSupportFragmentManager())
mViewPager = findViewById(R.id.viewpager1)
setupViewPager(mViewPager)
}
fun setupViewPager(viewPager :ViewPager):Unit {
var adapter : SectionsStatePagerAdapter = SectionsStatePagerAdapter(getSupportFragmentManager())
adapter.addFragment(Fragment1(),"Fragment1")
viewPager.setAdapter(adapter)
}
I'm getting val can't be reassigned...
Error:(65, 24) Smart cast to 'ViewPager!' is impossible, because 'mViewPager' is a mutable property that could have been changed by this time
For Android, it is common to use lateinit var because you create the object outside of constructor (in onCreate, etc). You can go with two route:
lateinit var variable:Type
var variable:Type?
I would recommend if your variable should be available when you are ready to use it. You do not need to do null check. lateinit mean late initialization. Kotlin use null to represent not yet initialized, so you cannot use nullable type and assign null on it.
If your variable is nullable, then you should go the second way.
Beside, if you are handling views, you should use Android extension to do it. You don't need to findViewById in Activity or Fragment yourself.
There are two things happening here.
First, as #gyosida points out, you have defined your mPager property as val instead of var so it cannot be reassigned in the line mViewPager = findViewById(R.id.viewpager1). As #Joshua points out, you either have to make it a var or you need to make it a lateinit val to solve the problem of it not being initialised with the class instance.
The second is represented by the actual error you describe of, 'mutable property that could have been changed', and you will continue to see this if you make it a var. The approach of using lateinit is most likely the better idea.
However, to explain this error, in your method declaration of:
fun setupViewPager(viewPager: ViewPager): Unit {
you have said that the argument for viewPager cannot be null. If it were, it would be viewPager: ViewPager?. So, if you pass something that could be null into it, you will get a compile error.
What Kotlin is telling you is that in between the lines:
mViewPager = findViewById(R.id.viewpager1)
and
setupViewPager(mViewPager)
something - imagine another method on another thread - could potentially have changed the value of mViewPager from that assigned instance to null. Therefore it's not safe to pass it in.
The only way to solve this without changing the method is supply a value that is guaranteed to be non-null. There are a few ways you could do that:
assign your value to a method-level variable that can't be interfered with, and supply that as the argument
only call your function if the value is non-null, e.g. mViewPager?.let{ pager -> setupViewPager(pager)}
assert that mViewPager will not be null, leaving any violations to fail at runtime, e.g. setupViewPager(mViewPager!!)