Stopping an app from crashing by checking if EditText is empty - android

So i made a Calculator with 2 EditText inputs, but i couldn't stop the app from crashing when the 2 fields are empty. I found some solutions for EditText of Text type but am stuck here because i am using a Number EditText.
Here is the code by the way:
{
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
fun buPlusClick(view: View){
var num1:Int=ednum1.text.toString().toInt()
var num2:Int=ednum2.text.toString().toInt()
var result = num1+num2
val resultprint = "The result Is : $result"
tvresult.text=resultprint
}
}

The error you're likely getting is a NumberFormatException. This is because ("" != [0-9]+) && value value !< Int.MAX_VALUE && !> Int.MIN_VALUE.
You have three options:
Check if it's empty first, as sandip mentioned.
Use toIntOrNull
Catch the exception.
toInt throws an exception (NumberFormatException) if the int is invalid. This means:
Not a number with the defined radix (default 10; an actual int. I.e. 16 is hex, but it's not applicable here)
The number is too big or too small (under Int.MIN_VALUE or over Int.MAX_VALUE).
The String is empty.
Checking if it's empty first solves half the problem; it can't be valid if it's empty. However, it doesn't solve it if there are letters or the number is too big.
You can use toIntOrNull() for this. It's just like toInt(), but it returns null if the conversion fails. You can use the elvis operator with a run block, or just use a simple if-statement to check if it's null, and handle the problems accordingly.
val num1: Int = ednum1.text.toString().toIntOrNull() ?: run {
// Notify the user the first number is invalid
return; // return from the method to avoid NPE's
}
val num2: Int = ednum2.text.toString().toIntOrNull() ?: run {
// Notify the user the second number is invalid
return;
}
if you don't understand what run does here, take a look at this question. You can also get rid of run entirely and assign a number value, just let it be null and handle it later, or something else.
The max positive value of an int is about 2.4 billion. If you expect numbers with a higher input than that, use Long, and equivalently toLongOrNull().
The last option is catching the error.
var num1: Int? = try { ednum1.text.toString().toInt() } catch (e: NumberFormatException) {
// You can do a lot of stuff in here; you can notify the user and `return` from the method,
// set it to null and handle it later, or assign an integer value.
null
}
var num2: Int? = try { ednum2.text.toString().toInt() } catch (e: NumberFormatException) {
// see my comments on the first block; same applies here
null
}
It is, in my opinion, slightly more bulky than toIntOrNull()( / toLongOrNull()), but it is an option.

You need to check first editText empty or not.
//Java
private boolean isEmpty(EditText editText) {
if (editText.getText().toString().trim().length() > 0)
return false;
return true;
}
//kotlin
private fun isEmpty(editText: EditText): Boolean {
return if (editText.text.toString().trim { it <= ' ' }.length > 0) false else true
}
Then do the following Code:
fun buPlusClick(view: View){
if(!isEmpty(ednum1) && !isEmpty(ednum2)) {
var num1:Int=ednum1.text.toString().toInt()
var num2:Int=ednum2.text.toString().toInt()
var result = num1+num2
val resultprint = "The result Is : $result"
tvresult.text=resultprint
}
}
Do the above check all of your functions.

Related

password validation no Character sequence ( kotlin android studio )

I have the task to create a password validation that has to consider some things. The only problem I have is that one of the criteria of the password validation is that the password must not contain any sequences, e.g. (12345), (abcdef), (asdfghjk). I have already searched a lot and do not know how to implement this. Can anyone help.
This is how I implemented it.
I also check that there is no sequence in backwards, for example (4321, dcba).
private fun noSequenzes(password: String) : Boolean {
val charRuns = listOf(
'0'..'9',
'a'..'z',
'A'..'Z',
"qwertzuiop".asIterable(),
"asdfghjklöä".asIterable(),
"yxcvbnm".asIterable()
)
var map = emptyMap<Char, MutableSet<Char?>>()
charRuns.forEach { run ->
run.forEach { char ->
val charsToAdd = mutableSetOf(run.elementAtOrNull(run.indexOf(char) + 1))
if (run is CharRange) {
charsToAdd.add(run.elementAtOrNull(run.indexOf(char) - 1))
}
if (map.contains(char)) {
map.get(char)!!.addAll(charsToAdd)
}
else {
map = map.plus(Pair(char, charsToAdd))
}
}
}
var sequenceCounter = 1
var recentChar: Char? = null
password.toCharArray().forEach { c ->
recentChar?.let { rc ->
val isSequence = map.any { me -> me.key == rc && me.value.contains(c) }
if (isSequence) {
sequenceCounter = sequenceCounter + 1
}
else {
sequenceCounter = 1
}
if (sequenceCounter >= 3) {
return false
}
}
recentChar = c
}
return true
}
Since you didn't give much detail into what code you already have and what you're stuck on about the logic, here's a very generalized description of a strategy you could use to do this:
Create a List<Iterable<Char>> that contains all the possible strings of characters that could be considered a range. For example:
val charRuns = listOf(
'0'..'9',
'a'..'z',
'A'..'Z',
"qwertyuiop".asIterable(),
//...
)
Iterate these runs to fill a MutableMap<Char, MutableSet<Char>>, where the keys are any of the characters from the runs, and the values are sets of all the chars that if they appear next in a string should be considered a consecutive sequence.
Iterate the potential password String, using the map to check the subsequent Char of each Char to see if it should be considered part of a sequence. Use a counter variable to count the current size of sequence found so far, and reset it whenever a non-sequence is found. If it ever rises above your threshold for allowable sequence size, reject the password immediately.

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}

Kotlin: How can I reduce child arrays into a single array?

I have a pice of code in Swift that reduces a list of TVSchedule objects into an array of TVMatch pobjects. Each TVSchedule, has a property called events, that is a list of TVMatches.
The code in swift is the following:
var matches: [TVMatch] {
let slots = timeSlots.reduce(into: [TVMatch]()) { (result, schedule) in
result.append(contentsOf: schedule.events)
}
return slots
}
I'm trying to do the same reduce in Kotlin and the code I have is the following:
val matches: ArrayList<TVMatch>
get() {
val slots = timeSlots.fold(arrayListOf<TVMatch>()) { result, schedule ->
result.addAll(schedule.events)
}
return slots
}
However, the Kotlin code gives me a type error, and does not compile. What is the problem here?
addAll returns a boolean, but the return value of the fold-operation should be of same type as the given initial object (in this case ArrayList).
You can solve that one easily by just adding result after your addAll-statement, e.g.:
result.addAll(schedule.events)
result // this is now the actual return value of the fold-operation
Alternatively just use apply or similar instead:
result.apply {
addAll(schedule.events)
} // result is the return value then
Note that you can actually simplify altogether using flatMap to just (side-note: if you use this approach the matches are evaluated only once of course, but flatMap is the star here anyway ;-))):
val matches = timeSlots.flatMap { it.events } // this is a new list! (note, if you do several mappings in a row, you may want to use timeSlots.asSequence().flatMap { }.map { }.toList() / or .toMutableList() instead
Alternatively if you really require the matches to be of type ArrayList, use flatMapTo instead:
val matches = timeSlots.flatMapTo(ArrayList()) { it.events }
You can of course keep the get() if you must, or just move the getting of the matches to its own function, e.g.:
fun getMatches() = timeSlots.flatMapTo(ArrayList()) { it.events }
Am I crazy, or can't you just replace the code with
val matches: List<TVMatch>
get() = timeSlots.flatMap { schedule -> schedule.events }
?

.find() doesn't execute its block on an empty list in kotlin

so today I stumbled on an interesting bug and I wanted to ask the reason why. I have the following:
val phone = contactDAO.phones?.find {
val phone = it.content
phone != null && !phone.startsWith("+")
} != null
if (phone) {...}
so yes phones could be null but it can also be empty.
It seems kotlin sees that is not null and goes to the .find
but realizes is empty and thus never executes the block inside.
why is this?
and is there a cleaner way to do this check along with .find?
Here is a simple example.
#JvmStatic
fun main(arr: Array<String>) {
val array = emptyArray<String>()
val foundItem = array.find {
it == "String" // This will never call
}
println(foundItem)
}
If your array is empty, find predicate condition will never call. This is no reason to call.
It already simple enough, you don't need to check for null in the predicate.
Example
val phones: List<String>? = listOf("1", "2", "+3", "4", "5")
println(phones?.find { it.startsWith("+") })
Output
+3
Example
val phones: List<String>? = null
println(phones?.find { it.startsWith("+") })
Output
null
Also just a head up, find will only match the first element or null if none is found, maybe you are most interested in filter, that returns a List with all the matching elements

Why can I invoke a fun without passing parameter name in Kotlin?

There are 4 parameters with default value in function joinToString, in my mind, I should pass parameter value by order when I omit parameter name.
So I think the Code println(letters.joinToString( transform={ it.toLowerCase() } ) ) is right.
But in fact the Code println(letters.joinToString { it.toLowerCase() } ) is right too, why?
fun <T> Collection<T>.joinToString(
separator: String = ", ",
prefix: String = "",
postfix: String = "",
transform: (T) -> String = { it.toString() }
): String {
val result = StringBuilder(prefix)
for ((index, element) in this.withIndex()) {
if (index > 0) result.append(separator)
result.append(transform(element))
}
result.append(postfix)
return result.toString()
}
fun main(args: Array<String>) {
val letters = listOf("Alpha", "Beta")
println(letters.joinToString { it.toLowerCase() } ) //It's Ok
println(letters.joinToString( transform={ it.toLowerCase() } ) ) //It's OK
}
Because you're using a different syntax.
If the last param of a method is a method reference then you can omit the parenthesis and just pass in the function with the { brackets.
it in this case becomes T that you were passing into the function
println(letters.joinToString { it.toLowerCase() } )
Below is what you thought you were entering. This wouldn't compile and would require the named argument or for the params to be in the right order. You would also have to change the syntax from using it to using the regular functional syntax
println(letters.joinToString(it.toLowerCase()))
In addition to #Dan's answer, you don't need to provide a named argument, but if you do so then you're forced to use the named argument for all the following arguments (from the documentation: "all the positional arguments should be placed before the first named one"). In your case the only named argument you're providing is the last one, and all other arguments have default values so you're not forced to provide them, as long as the default value is fine for you.

Categories

Resources