Issue
I am new using Kotlin and have implemented a recyvclerview list and now I'm using putExtra() and getStringExtra() intents to open in the same activities to avoid creating too many activities. So far it is working fine but I'm noticing my list is getting to long, and I'm planning on adding more. Is there a way to create a list of the numbers and call it into the intent? or maybe create another file class with the numbers and call it into the intent? If so how can it be done?
val intent = Intent(this, HNSPSFOC1::class.java)
val drinks = intent.getStringExtra("Drinks").toString()
val food = intent.getStringExtra("FastFood").toString()
when {
drinks == "1" -> { intent.putExtra("CoffeeShops","1")}
drinks == "2" -> { intent.putExtra("CoffeeShops","2")}
drinks== "3" -> { intent.putExtra("CoffeeShops","3")}
drinks == "4" -> { intent.putExtra("CoffeeShops","4")}
drinks == "5" -> { intent.putExtra("CoffeeShops","5")}
drinks == "6" -> { intent.putExtra("CoffeeShops","6")}
drinks == "7" -> { intent.putExtra("CoffeeShops","7")}
drinks == "8" -> { intent.putExtra("CoffeeShops","8")}
drinks == "9" -> { intent.putExtra("CoffeeShops","9")}
drinks == "10" -> { intent.putExtra("CoffeeShops","10")}
drinks == "11" -> { intent.putExtra("CoffeeShops","11")}
drinks == "12" -> { intent.putExtra("CoffeeShops","12")}
drinks == "13" -> { intent.putExtra("CoffeeShops","13")}
drinks == "14" -> { intent.putExtra("CoffeeShops","14")}
drinks == "15" -> { intent.putExtra("CoffeeShops","15")}
drinks == "16" -> { intent.putExtra("CoffeeShops","16")}
drinks == "17" -> { intent.putExtra("CoffeeShops","17")}
drinks == "18" -> { intent.putExtra("CoffeeShops","18")}
drinks == "19" -> { intent.putExtra("CoffeeShops","19")}
drinks == "20" -> { intent.putExtra("CoffeeShops","20")}
food == "1" -> {intent.putExtra("FastFood","1")}
food == "2" -> { intent.putExtra("FastFood","2")}
food== "3" -> { intent.putExtra("FastFood","3")}
food == "4" -> { intent.putExtra("FastFood","4")}
food == "5" -> { intent.putExtra("FastFood","5")}
food == "6" -> { intent.putExtra("FastFood","6")}
food == "7" -> { intent.putExtra("FastFood","7")}
food == "8" -> { intent.putExtra("FastFood","8")}
food == "9" -> { intent.putExtra("FastFood","9")}
food == "10" -> { intent.putExtra("FastFood","10")}
food == "11" -> { intent.putExtra("FastFood","11")}
food == "12" -> { intent.putExtra("FastFood","12")}
food == "13" -> { intent.putExtra("FastFood","13")}
food == "14" -> { intent.putExtra("FastFood","14")}
food == "15" -> { intent.putExtra("FastFood","15")}
food == "16" -> { intent.putExtra("FastFood","16")}
food == "17" -> { intent.putExtra("FastFood","17")}
food == "18" -> { intent.putExtra("FastFood","18")}
food == "19" -> { intent.putExtra("FastFood","19")}
food == "20" -> { intent.putExtra("FastFood","20")}
}
Solution
I'm just posting this as an answer so I can explain it without the comment length limitation, so don't mark it as the correct one or anything! And uh it's a bit longer than I intended but hopefully it helps you understand coding in general a bit more
So you've edited your question with a longer when
block that handles a food
variable as well as a drinks
one. There's a big problem with this but I'll get to that in a bit. Let's just look at drinks
for now:
when {
drinks == "1" -> { intent.putExtra("CoffeeShops","1")}
drinks == "2" -> { intent.putExtra("CoffeeShops","2")}
drinks == "3" -> { intent.putExtra("CoffeeShops","3")}
...
}
The first thing you should notice is that you're doing pretty much the same thing over and over. It wasn't fun writing that all out, right? Plus there's the possibility you could make a mistake and use the wrong value, or if you had to change this in the future, you'd have to edit every line and possibly make an error there. There's always the chance to make an error, but that chance grows when you have a lot of repetitive work like this.
Just as a general rule, if you find yourself repeating the same thing, that's usually a sign that you should write a bit of logic that works out the correct value or correct action based on some values, and just does the appropriate thing.
So what would that look like here? Well what's in common for every line?
- always calls
putExtra
on theintent
variable - always passes
"CoffeeShops"
as the key - uses a changing value
Really, the only unique bit of data here is the value parameter being passed to putExtra
. So instead, you could use your when
block to just work out what that value should be, and then whatever the result, use that in your putExtra
call:
val drinksValue = when {
drinks == "1" -> "1"
drinks == "2" -> "2"
drinks == "3" -> "3"
...
}
intent.putExtra("CoffeeShops", drinksValue)
Already you should be able to see how much better that is - the intent.putExtra
call is only written once, the "CoffeeShops"
key is only written once, it's way less effort to write and maintain and easier to spot potential bugs because you only have to look at one thing.
Hopefully you've also noticed something about the pattern on the left of the when
block. There's another way to write that actually - this is more about learning language features than can help you than just structuring your logic so you don't have to repeat yourself, so don't worry if you didn't know it, but it should make something clearer:
// putting a variable in parentheses here makes it the value that all the
// branches are checked against - so you don't need to write "drinks =="
val drinksValue = when(drinks) {
"1" -> "1"
"2" -> "2"
...
}
So now it's clearer what's happening - if the value of drinks
is "1"
, our result is "1". If the value is "2", our result is "2", etc.
That's... definitely repeating ourselves! We've turned all the putExtra
calls into a single line, but we have a lot of lines saying if this value is "1", use "1" - we can just use the drinks
value as-is, right? No need for the when
checking every case
intent.putExtra("CoffeeShops", drinks)
Now it literally is a single line. You can wrap that in some code to validate the range of correct values, which is also kinda what the when
was doing, but there's a pattern here - and if we're smart, we can work out a way to check if it's valid. It's a String
which makes it a little harder, but all the valid values are a range of numbers, so we can do some conversion:
// Try to parse 'drinks' as an integer and check if it's in the range 1 to 20
// If it can't be parsed as an Int (say it's "a" for some reason) the result
// will be null, and 'null in (1..20)' returns false - works for all invalid values!
if (drinks.toIntOrNull() in (1..20)) {
intent.putExtra("CoffeeShops", drinks)
}
So you added another food
variable you want to handle as well, right? Well, that's completely separate from drinks
, so you want to do both. And if you look at your when
block... it's exactly the same logic, right?
when {
drinks == "1" -> { intent.putExtra("CoffeeShops","1") }
...
food == "1" -> { intent.putExtra("FastFood","1") }
}
Same thing, it's just the key is changing now, and obviously the value you're putting in the extra is from food
. We can just do the exact same thing as before - so now you've got:
if (drinks.toIntOrNull() in (1..20)) {
intent.putExtra("CoffeeShops", drinks)
}
// same thing but with 'food' - validate the value, insert with appropriate key
if (food.toIntOrNull() in (1..20)) {
intent.putExtra("FastFood", food)
}
You're handling drinks
, and then you're handling food
. But hey - there's repetition here too, right? Not a lot, and this is where it becomes a judgement call, but if you had more of these variables, you'd probably want to avoid the repetition. So we could break out this logic into a separate function that has all the common stuff, and just pass in the things that change:
fun tryInsertValue(value: Int, key: String) {
if (value.toIntOrNull() in (1..20)) {
intent.putExtra(key, value)
}
}
Then you can call it with
tryInsertValue(drinks, "CoffeeShops")
tryInsertValue(food, "FastFood")
I'm assuming some things here - the valid number range is always from 1 to 20, the function can see intent
- but you could always pass that intent in as a parameter, or pass in a valid range to check. This can get as involved as you want, and it's where you have to decide if it's worth it or not in your particular case, but hopefully you get the general idea and a better sense of how to approach these things. Break stuff down, look for commonalities, and avoid repeating yourself!
This bit's important
So the other problem with your current code is that when
blocks go through each case in order, looking for the first match, and then they evaluate the branch for that match. Then the when
block exits.
Say your drinks
value is "2"
and food
is "1"
. First the when
block checks if drinks
is "1"
- it isn't. Then it moves to the next check - is drinks
"2"
? Yes it is, so you do intent.putExtra("CoffeeShops","2")
and exit the block.
When does it ever get to checking the food == "1"
case? It doesn't. It will always hit the drinks == "2"
one first, which will be true, and that's it, end of block, no more checks. So if you did write out every case, you'd need a separate when
for all the drinks
stuff, and another one for all the food
stuff. So they both run, completely independently. The reason to put them all in one block is if you wanted it to act that way, and only set the food
value if drinks
didn't match anything. Sometimes you want that, but it seems like you don't here
whew
Answered By - cactustictacs
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.