How to check string has digit only in kotlin - android

I'm working in Kotlin Android.
The string is coming from the server, and it might contain digit, character, empty string or null value. I want to convert that value into double because I want to compare values.
So is there any better way to check that string contains only digit value and not empty or null in a Kotlin way. The list is huge, so I want an efficient way.
Price.kt
data class Price(
var value: String? = null
)
main.kt
val defaultValue : Double = 4.23
val list = listOf(Price("2.33"), Price("fr23"), Price(""), Price(null), Price("4.23"), Price("12.23"))
list.forEach{
if(it == defaultValue){
println("Found It")
}
}

Kotlin already has an efficient solution: toDoubleOrNull
Parses the string as a Double number and returns the result or null if
the string is not a valid representation of a number.
if (list.any { it.value.toDobleOrNull() == defaultValue }) {
println("Found It")
}

Related

I use proper way to compare two strings but still the program is malfunctioning [duplicate]

I'm studying kotlin, but I'm very disappointed, I can not compare two Strings.
What is the right way to compare.
btn_login.setOnClickListener {
val login = input_email.text.trim()
val pass = input_password.text.trim()
if( login.equals( pass ) ){
startActivity<MainActivity>()
}
if (login?.equals(other = pass)){
startActivity<MainActivity>()
}
if (login == pass){
startActivity<MainActivity>()
}
}
According to documentation for structual equality use ==. It is translated to a?.equals(b) ?: (b === null).
In you case convert login and pass from SpannableStringBuilder to String.
val login = input_email.text.trim().toString()
Here is the example for matching the two strings using kotlin.
If you are using == (double equals) for matching the string then it's compare the address & return maximum time wrong result as per java documentation so use equals for the same
If you want to use equal ignore case then pass the true in the equals method of String
if (s1.equals(s2,true))
other wise you can just use this without boolean like
if (s1.equals(s2,false)) or if (s1.equals(s2))
compleate code is below
fun main(args: Array<String>) {
val s1 = "abc"
val s2 = "Abc"
if (s1.equals(s2,true))
{
println("Equal")
}
else
{
println("Not Equal")
}
}
Covert both the SpannableStringBuilder to string with toString, this should work.
val login = input_email.text.trim().toString()
val pass = input_password.text.trim().toString()
if (login == pass){
startActivity<MainActivity>()
}
1. == :
if ( string1 == string2 ){...}
2. equals :
Indicates whether some other object is "equal to" this one.
Implementations must fulfil the following requirements:
Reflexive: for any non-null reference value x, x.equals(x) should
return true.
Symmetric: for any non-null reference values x and y, x.equals(y)
should return true if and only if y.equals(x) returns true.
Transitive: for any non-null reference values x, y, and z, if
x.equals(y) returns true and y.equals(z) returns true, then
x.equals(z) should return true
Consistent: for any non-null reference values x and y, multiple
invocations of x.equals(y) consistently return true or consistently
return false, provided no information used in equals comparisons on
the objects is modified.
/** * Returns `true` if this string is equal to [other], optionally ignoring character case. * * #param ignoreCase `true` to ignore character case when comparing strings. By default `false`. */
public fun String?.equals(other: String?, ignoreCase: Boolean = false): Boolean
3. compareTo :
public override fun compareTo(other: String): Int
Compares this object with the specified object for order. Returns zero
if this object is equal to the specified other object, a negative
number if it's less than other, or a positive number if it's greater
than other.
public fun String.compareTo(other: String, ignoreCase: Boolean = false): Int
Compares two strings lexicographically, optionally ignoring case
differences
i know this is way too late, but as a newbie learning Kotlin, i had the same doubts.
then i came across this wonderful article that articulates the various string comparison types in Kotlin and the differences between them all.
in short both == and .equals() can be used to compare the value of 2 strings in kotlin.
hopefully that helps
With case checking
String a=.....
String b=.....
if(a==b){
}
IgnoreCase
if(a.equals(b,false))
KOTLIN:
if (editText1.text.toString() == editText2.text.toString() ) {
println("Should work now! The same value")
}
Try the following solution, see if it helps:
val passStr: String = textView.text.toString()
if( loginStr.compareTo(passStr, false) ){
startActivity<MainActivity>()
}
Try this surely will work.
val style = buildString { karthik}
val style2 = buildString { karthik }
var result = style.equals(style2)
if(result){//Do something}

Why value null after converting in int in kotlin

Hey I am working in android kotlin. I am getting double value in the form of string from server. I am converting that value in Int and checking that value is not null using toIntOrNull(). But I am getting 0 all the time.
Value coming from server
"value": "79.00"
My Data class
import android.os.Parcelable
import kotlinx.android.parcel.Parcelize
#Parcelize
data class Detail(
val value: String? = null,
) : Parcelable {
val valueInDouble by lazy {
value?.toDoubleOrNull() ?: Double.NaN
}
val valueInInt by lazy {
value?.toIntOrNull() ?: 0
}
}
whenever I print the value of valueInInt in console it returns 0. I know that 0 is coming because of toIntOrNull() but my value is coming from server which is not null. But I don't understand why this is happening. Can someone guide me please?
Expected Output
79
Actual Output
0
If the String value has a decimal in it, it cannot be parsed as an integer, so toIntOrNull() will return null.
You should parse as a Double and then convert the Double to an Int based on whatever type of rounding is appropriate for your use case.
val valueInInt by lazy {
value?.toDoubleOrNull()?.roundToInt() ?: 0
}

Multi type object in kotlin

from an API call i get as response a body with this structure
open class BaseResponseEntity {
#SerializedName("result")
val result: ResultEnum = ResultEnum.NONE
#SerializedName("errorCode")
val errorCode: String = ""
#SerializedName("errorMessage")
val errorMessage: String = ""
#SerializedName("successMessage")
val successMessage: String = ""
#SerializedName("value")
val code: LastPaymentCodeModel?
}
where the field "value" can be three types: null, String or LastPaymentCodeModel. How can i get this?
I managed to put a ? so that both null and LastPaymentCodeModel are handled, but i don't know how to handle the String type too.
I think the best approach would probably be to use type Any? for code.
Then you should write a custom GSon serializer/deserilizer (JsonDeserializer<BaseResponseEntity>) for the BaseResponseEntity object.
In this Json deserializer, you would need to check the type of value (e.g is it a string or a data structure) and decode it to the correct object type.
Alternative, to avoid the use of Any?, you could leave the model exactly as you have it. You will still need to write a custom JsonDeserializer, however if value is a string then it would still create a LastPaymentCodeModel, using the string value as one of it's properties.

Pass values as parameters if not null or empty Kotlin

I have text values I retrieve from text inputs. I want to allow the user to not fill in these inputs. But if the user has not filled one or more values I want to display default values for these inputs.
I have a data class that looks something like this:
#Parcelize
data class Profile(
val firstName: String = "",
val lastName: String = "",
val description: String = "",
val imageUri: String = ""
) : Parcelable
On click I call a method from my ViewModel class and pass it the current input values which is then persisted using a Repository class:
viewModel.createProfile(
etFirstName.text.toString(),
etLastName.text.toString(),
etProfileDescription.text.toString(),
profileImageUri.toString()
)
// The createProfile function itself
fun createProfile(
firstName: String = "John",
lastName: String = "Doe",
description: String = "Default Description",
imageUri: String = ""
) {
val profile = Profile(firstName, lastName, description, imageUri)
// Persist data
}
In a another fragment I set some UI data using this persisted data like this:
private fun observeProfile() {
viewModel.getProfile()
viewModel.profile.observe(viewLifecycleOwner, Observer {
val profile = it
tvName.text = getString(R.string.profile_name, profile.firstName, profile.lastName)
tvDescription.text = profile.description
ivProfileImage.setImageURI(Uri.parse(profile.imageUri))
})
}
So currently createProfile expects 4 arguments. I'm able to pass less because I have optional parameters, but how can I conditionally pass arguments to createProfile based on if the value is non null or empty. I can of course create checks for each value, but what is the best way to approach this?
Update
I don't think I was clear enough in my original question, because I don't only pass values from text inputs to createProfile. profileImageUri is a class variable of type Uri? and is initially set to null. The user can select an image and this variable is updated with the image data. The reason I'm passing and storing the image data as a String is because all the profile data also gets persisted to Firestore so Strings are easier to work with.
Compared to your own answer, I'd create a helper function
fun CharSequence?.ifNullOrEmpty(default: String) = if (this.isNullOrEmpty()) default else this.toString()
And use it as
viewModel.createProfile(
etFirstName.text.ifNullOrEmpty("John"),
etLastName.text.ifNullOrEmpty("Doe"),
etProfileDescription.text.ifNullOrEmpty("Default Description"),
profileImageUri.ifNullOrEmpty("Default Uri")
)
EDIT: given the update, I'd consider
fun Any?.ifNullOrEmpty(default: String) =
if (this == null || (this is CharSequence && this.isEmpty()))
default
else
this.toString()
I have found a workaround.
Turns out it's possible to pass if-else statements as parameters, because if statements are expressions in Kotlin:
viewModel.createProfile(
if (!etFirstName.text.isNullOrEmpty()) etFirstName.text.toString() else "John",
if (!etLastName.text.isNullOrEmpty()) etLastName.text.toString() else "Doe",
if (!etProfileDescription.text.isNullOrEmpty()) etProfileDescription.text.toString() else "Default Description",
if (profileImageUri != null) profileImageUri.toString() else ""
)
Using this approach I also don't have to set default values for my data class variables and for my createProfile function parameters.
I additionally added a check in my observeProfile function so if profileImageUri is null it won't try to set the image:
// ...
if (profile.imageUri.isNotEmpty()) {
ivProfileImage.setImageURI(Uri.parse(profile.imageUri))
}
// ...
My initial idea doesn't seem to be possible using a data class. It does seem to be possible using a regular class and varargsbut it has problems:
#Parcelize
class Profile(
vararg val params: String
) : Parcelable
...
val params = arrayOfValues.filter{ !it.isNullOrBlank() } // filter out all unwanted data
val profile = Profile(*params) // pass every param separately using spread operator
Main problem here is that the parameters themselves are obfuscated. I can still get the reference to individual parameters using an index and do stuff with them, but it doesn't work as nicely.
I think what you want to use is the Elvis Operator in Kotlin: ?:.
val test = exampleExpression ?: "alternative value"
If the expression to the left of ?: is not null, the elvis operator returns it, otherwise it returns the expression to the right. Note that the right-hand side expression is evaluated only if the left-hand side is null.
viewModel.createProfile(
etFirstName.text.toString() ?: "John",
etLastName.text.toString() ?: "Doe",
etProfileDescription.text.toString() ?: "Default Description",
profileImageUri.toString() ?: "Default Uri"
)

What's the point of having a default value in sharedPref.getString?

I'm accessing my Android apps SharedPreferences via
private val sharedPref = PreferenceManager.getDefaultSharedPreferences(context)`
and then attempting to get data from it using
val lat: String = sharedPref.getString("MyKey", "Default")
But this line gives me an error reading "Type mismatch. Required String, found String?"
According to the documentation the second parameter in the getString method says "Value to return if this preference does not exist. This value may be null."
So what's the point of having a default value then if the value can be null? I cannot seem to get the default value to ever be used and the only way I can get my code to work is to use the elvis operator and rewrite my code as:
val lat: String = sharedPref.getString("MyKey", "Default") ?: "Default"
Which looks ugly. Am I crazy? What am I missing?
Consider this in a such way:
Every String preference in SharedPreferences can exist or not and can be null or not. So the code
val lat: String = sharedPref.getString("MyKey", "Default") ?: "Not Set"
will return:
Default if the preference with this Key doesn't exists (means there is no mapping for this Key)
Not Set if the preference exists, but is null (mapping Key to null created)
any other value if the preference exists and the value of the mapping isn't null.
Update
Apparently, SharedPreferences are much less smart I thought it was. Having this code internally:
String v = (String)mMap.get(key);
return v != null ? v : defValue;
it will return null only if we'll pass null as a default value (and there were no value saved). This means we actually don't need an elvis option and we will not get "Not Set" value. This method returns nullable value, just because it allows you to pass nullable as a default value.
It's because kotlin Null-Safety is kick in when reading the following code:
val lat: String = sharedPref.getString("MyKey", "Default")
if you visit the SharedPreferences code, you can see the following code:
#Nullable
String getString(String key, #Nullable String defValue);
which is give us a probability to use null as defValue parameter. So, Kotlin try to guard it and give you the matching error:
"Type mismatch. Required String, found String?"
You can fix the problem by enabling nullable for your String variable with:
val lat: String? = sharedPref.getString("MyKey", "Default")
though this against Kotlin type system purpose:
Kotlin's type system is aimed at eliminating the danger of null references from code, also known as the The Billion Dollar Mistake.
SharedPreferences is an abstraction over Key/Value databasing provided by Google, how you use it is up to you. If you dislike this syntax, then create a wrapper or extension for your getString(). Just to give an example:
fun PreferenceManager.getStringTheFancyWay(key: String, defaultValue: String): String {
return getString(key, defaultValue) ?: defaultValue
}
val value = getStringTheFancyWay("a", "b")
Personally I dislike this, because null allows for a better control flow over non-existing keys.
This is how I use SharedPreferences
val preferences = PreferenceManager.getDefaultSharedPreferences(context)
val value = preferences.getString("username", null)
if (value != null) {
toast("Hello $value")
} else {
toast("Username not found")
}
or
preferences.getString("username", null)?.let { username ->
toast("Hello $username")
}
Notice the difference?
The fact is simple, just imagine you haven't saved any value regarding to that key(for your case 'MyKey') and tried to get the value for that key(for your case 'MyKey'). What will SharedPreference return ? It will simply return the default value.
You will see that, you must assign null or any other string to default for String type, 0 or any other int value to default for integer type and true or false default value for bolean type. I hope you got the answer.

Categories

Resources