Home > Software design >  intent.putExtra getting too long and not convenient
intent.putExtra getting too long and not convenient

Time:07-03

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

CodePudding user response:

Your drinks variable is already string. You don't have to use when statement.It is unnecessary. You can pass directly this variable like this.

intent.putExtra("Coffee Shops", drinks)

CodePudding user response:

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 the intent 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

  • Related