Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Trying to get a when expression to show the result on the ui in kotlin

Tags:

kotlin

I have been stuck making this metric converter app for over a week I keep going back to the previous codelabs that explain how to make a tip calculator but when I try to apply the same method to this app that I'm trying to make it doesn't have any errors but the app crashes whenever I try to test it to see if I can get the functionality to work this is my last resort. I've tried to do when statements but I kept getting the error that certain branches would never be reached. if anyone can point me in the right direction as to what I'm doing wrong or what's missing from my code. I'm all ears.

package com.example.metricconversion

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import com.example.metricconversion.databinding.ActivityMainBinding



class MainActivity : AppCompatActivity() {

    private lateinit var binding: ActivityMainBinding
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(R.layout.activity_main)
        setContentView(binding.root)
        binding.conversionTo.setOnClickListener { convertMetric() }

    }


    fun convertMetric() {
        val stringInTextField = binding.howMuchStuffWeTalking.text.toString()
        val amountIQ = stringInTextField.toDouble()
        val selectedId = binding.unitThatNeedsToBeConverted.checkedRadioButtonId
        val selectedId2 = binding.toBeConverted.checkedRadioButtonId
       // val grainToQtr = R.id.Grain and R.id.quarter1
        //val grainToSt= R.id.Grain and R.id.quarter1
        //val grainToLb = R.id.Grain and R.id. pound1
        //val grainToTon= R.id.Grain and R.id.Ton1
        val st = R.id.Grain and R.id.stone1


        // code to convert grain to the other options

        //code to convert grain to the other options
        when (selectedId and selectedId2) {
            R.id.Grain and R.id.Ounce1 -> {
                amountIQ / 437.5
            }


        }
        when (selectedId and selectedId2) {
            R.id.Grain and R.id.quarter1 -> amountIQ * 0.000005714

        }

        when (selectedId and selectedId2) {
            R.id.Grain and R.id.pound1 -> amountIQ * 0.0001429
        }

        when (selectedId and selectedId2) {
            R.id.Grain and R.id.Ton1 -> amountIQ / 1.4e+7
        }
        when (selectedId and selectedId2) {
            st -> {
                amountIQ * 0.0000102
            }
        }

        binding.metricConverted.text=getString(R.string.end_result,convertMetric())

    }
}
like image 210
codingNoob Avatar asked Oct 15 '25 21:10

codingNoob


1 Answers

Problems with your code:

  1. Using and to check two values for equality at the same time is not viable. The and function does a bitwise operation to merge the two numbers together. There are many possible inputs that could merge to the same solution, so you will get false positives. Instead you could use the to infix function to combined the two numbers into a Pair wrapper object so they are both preserved for the comparison.

  2. You have a series of individual when statements, each with only a single condition. It doesn't make sense to use a when statement with a single condition. Usually a single condition would be represented with an if statement instead of when statement. But I'm guessing you didn't mean for these to be separate when statements, based on what I'm seeing.

  3. Your when statements are not actually doing anything. Their branches resolve to a number, but you're not doing anything with that number (not assigning it to a variable or logging it or showing it in the UI, etc.). So they are useless. Your statement at the bottom isn't getting the result of any of the when statements, but is instead recursively calling the same function again. This function doesn't return anything, so that's useless. Even if it did return a number, the recursive call will create an infinite loop, resulting in a stack overflow.

So first, to just fix your code (we can discuss a better way of doing it later):

  1. We replace and with to.
  2. We merge all the when statements into a single statement.
  3. We store the result of the when statement in a variable and use that variable to set the text in the last line of the function. When you use a when statement with a subject (something in parentheses that is compared for each branch) or to get a result, you have to cover every possible case, so an else branch must also be added.
    fun convertMetric() {
        val stringInTextField = binding.howMuchStuffWeTalking.text.toString()
        val amountIQ = stringInTextField.toDouble()
        val selectedId = binding.unitThatNeedsToBeConverted.checkedRadioButtonId
        val selectedId2 = binding.toBeConverted.checkedRadioButtonId

        // code to convert grain to the other options

        val result = when (selectedId to selectedId2) {
            R.id.Grain to R.id.Ounce1 -> amountIQ / 437.5
            R.id.Grain to R.id.quarter1 -> amountIQ * 0.000005714
            R.id.Grain to R.id.pound1 -> amountIQ * 0.0001429
            R.id.Grain to R.id.Ton1 -> amountIQ / 1.4e+7
            R.id.Grain to R.id.stone1 -> amountIQ * 0.0000102
            else -> error("Unsupported selection pair")
        }

        binding.metricConverted.text = getString(R.string.end_result, result.toString())
    }

Above, the error() call will crash your app. You need to make sure you cover every possible combination that could occur. During development, this is suitable, but for production you might want to change the behavior so it shows an error message in the UI of the app and doesn't crash.

Now, regarding the overall design, it is quite fragile because you have UI layout details so tightly coupled to your app's behavior. All these formula calculations should probably be defined in a separate class, possibly an Enum class. You could create a Map in your Activity file that links the UI elements to the behavior class(es), and then in your when statement, you could use the UI elements to pull the associated behavior from the map. This would be more maintainable, and make it easier for you to avoid forgetting something as you add/modify functionality. I say this just to get you thinking about it, but it's probably too much for a beginner project right now. I don't have time to explain in detail how I would do all of that for your case.

like image 191
Tenfour04 Avatar answered Oct 18 '25 16:10

Tenfour04



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!