I am new to kotlin and I am trying an execise.
I want to calculate the tip as % of the cost of the service.I enter my cost of service in an EditText... so far so good.
now I want to convert this the value I entered to double, which the datatype I need for my calculation.
this is my code:
package com.example.tiptime2
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import com.example.tiptime2.databinding.ActivityMainBinding
class MainActivity : AppCompatActivity() {
lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
binding.calculate.setOnClickListener { calculateTip() }
}
fun calculateTip(){
val myTextString= binding.costOfService.text.toString()
val myCost = myTextString.toString()
val cost = myCost.toDouble()
}
}
androidStudio doesn't recognize toDouble()
why??
You're casting to .toString() twice and you need to update the data-binding. Roughly alike:
val cost = Double.parseDouble(binding.costOfService.text.toString())
// some calculations
binding.costOfService.setText(String.valueOf(cost))
Instead of handling single values, it's common to bind a view-model, which has all of them.
I suggest you explicit define variables type for debugging
fun calculateTip() {
val costText: String = binding.costOfService.text.toString()
val cost: Double = costText.toDouble()
}
Still your code looks valid!
Related
I am working in app with two languages
in autocomplatetextview i want to change values according to the language of device
i try this code
var EGP = getString(R.string.egyptian_pound_egp)
var USD = getString(R.string.american_dollar_usd)
var SAR = getString(R.string.Saudia_Ryal)
var KWD = getString(R.string.Kuwaiti_Dinar)
and full code of MainActivity
package com.example.currency
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Adapter
import android.widget.ArrayAdapter
import android.widget.AutoCompleteTextView
import android.widget.Button
import androidx.annotation.StringRes
import androidx.core.widget.addTextChangedListener
import com.google.android.material.internal.ContextUtils.getActivity
import com.google.android.material.textfield.TextInputEditText
class MainActivity : AppCompatActivity() {
var EGP = getString(R.string.egyptian_pound_egp)
var USD = getString(R.string.american_dollar_usd)
var SAR = getString(R.string.Saudia_Ryal)
var KWD = getString(R.string.Kuwaiti_Dinar)
lateinit var convertButton: Button
lateinit var amount: TextInputEditText
lateinit var result: TextInputEditText
lateinit var from: AutoCompleteTextView
lateinit var to: AutoCompleteTextView
val listValue = mapOf(
USD to 0.052356,
EGP to 1.0,
SAR to 0.197040,
KWD to 0.0166838
)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
initalizeViews()
populateMenu()
convertButton.setOnClickListener {
calcResault()
}
amount.addTextChangedListener {
calcResault()
}
}
private fun initalizeViews() {
convertButton = findViewById(R.id.button)
amount = findViewById(R.id.AmountTIET)
result = findViewById(R.id.ResultTIET)
from = findViewById(R.id.FromACTV)
to = findViewById(R.id.ToACTV)
}
private fun populateMenu() {
val currencyList = listOf(EGP, USD, SAR, KWD)
val adapter = ArrayAdapter(this, R.layout.list_currency, currencyList)
from.setAdapter(adapter)
to.setAdapter(adapter)
}
private fun calcResault(){
if (amount.text.toString().isNotEmpty()) {
result.setText(
String.format(
"%.2f", listValue.get(to.text.toString())!!.times(
amount.text.toString().toDouble()
.div(listValue.get(from.text.toString())!!)
)
)
)
} else {
amount.setError(getString(R.string.amount_required))
}
}
}
after testing some codes , i found that getString(R.string.xxx) the reason of the crashing
when change getString(R.string.xxx) with string value the app opening with no problem
but i want to change values according to the language of device
getString requires your Activity to have a Context, and at construction time it doesn't have one. So when you define those top-level variables that are initialised at construction time, your getString calls fail. The error log will tell you this, that you're trying to do something with a null Context or similar.
The context shows up somewhere around onCreate, so if you can guarantee those values won't be used until the Activity is CREATED (i.e. you won't be reading them until onCreate or later) then you could use a lazy delegate. That only initialises them when they're first read - so if you're reading them when the Activity has its Context, the getString call works fine!
val EGP = by lazy { getString(R.string.egyptian_pound_egp) }
val USD = by lazy { getString(R.string.american_dollar_usd) }
val SAR = by lazy { getString(R.string.Saudia_Ryal) }
val KWD = by lazy { getString(R.string.Kuwaiti_Dinar) }
But the problem here is you're not first reading these in onCreate or later - it happens in the next line where you build a Map using those values, which is another top-level variable that's initialised at construction. So you don't get the benefit of the lazy because it's called too early.
You can fix this by making that map lazy too:
val listValue by lazy { mapOf(
USD to 0.052356,
EGP to 1.0,
SAR to 0.197040,
KWD to 0.0166838
)}
Now listValue won't be initialised until it's read either! So it won't try to read those other values until it's actually accessed - so same deal, as long as listValue isn't read by something before onCreate, it should be fine.
This is the kind of thing you have to watch out for with lazy delegates in Android lifecycle components like Activity and Fragment, or anywhere you need lazy initialisation really. Make sure it's not being read too early by something else, and make those lazy too if appropriate.
Using lazy delegates requires your variables to be vals though - if you need to be able to change them, make them lateinit instead and initialise them manually as soon as you can. You could keep listValue as a lazy if you want, just make sure the lateinit vars it initialises from are assigned before it's accessed
Make those be either lateinit var or use by lazy {} to defer initialization. You cannot call getString() until after super.onCreate() has been called in your onCreate() function.
Try this
(CAUTION: You values will be re-initialized every time onCreate() method called)
lateinit var EGP: String
lateinit var USD: String
lateinit var listValues: Map<String, Double>
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
EGP = getString(R.string.egyptian_pound_egp)
USD = getString(R.string.american_dollar_usd)
listValues = mapOf(
USD to 0.052356,
EGP to 1.0
)
//Rest of your code
}
This is my first post and I am brand new to coding so please let me know if I've missed anything for getting some help.
I'm taking the Google Android Dev tutorials. The tutorial is walking me through creating a dice roll app. I completed that and for an extra challenge practice at the end it recommends getting two results from one button click.
I tried doing that in this code:
package com.example.diceroller
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Button
import android.widget.TextView
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val rollButton: Button = findViewById(R.id.button)
rollButton.setOnClickListener { rollDice() }
rollButton.setOnClickListener { rollDice2() }
}
private fun rollDice() {
val dice = Dice(6)
val diceRoll = dice.roll()
val resultTextView: TextView = findViewById(R.id.textView)
resultTextView.text = diceRoll.toString()
}
private fun rollDice2() {
val dice2 = Dice2(6)
val diceRoll2 = dice2.roll2()
val resultTextView: TextView = findViewById(R.id.textView2)
resultTextView.text = diceRoll2.toString()
}
}
class Dice(private val numSides: Int) {
fun roll(): Int {
return (1..numSides).random()
}
}
class Dice2(private val numSides: Int) {
fun roll2(): Int {
return (1..numSides).random()
}
}
I don't get any errors, but when I run the app it only shows one result (the second result). Again, I'm new to all this and maybe I'll learn it later, but looking for some help on why it only spits out one result. Any help is greatly appreciated and thank you in advance.
It's not made clear by the documentation for setOnClickListener, but a View (which a Button is a type of) can only have one click listener. So when you do this:
rollButton.setOnClickListener { rollDice() }
rollButton.setOnClickListener { rollDice2() }
you're setting a listener that calls rollDice(), and then replacing it with another one that calls rollDice2(). You need to do everything in a single listener!
rollButton.setOnClickListener {
rollDice()
rollDice2()
}
so when you click the button, it'll run the code in that lambda function you're passing in as your listener, so it'll call rollDice() and then rollDice2().
As a general rule, if a function is named like setListener, with a set, then it's usually a single listener that you can set (or unset, usually with null). If it's named something like addListener, with an add, that implies you can add more to what's already there, i.e. you can have multiple listeners or whatever.
I'm not saying this will always be true (always check the documentation, or the source code if you can! See what it's actually doing) but it's a good rule of thumb in my experience - but you should always check if you're unsure!
You can also achieve the same result by rolling the same dice twice
package com.example.diceroller
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Button
import android.widget.TextView
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val rollButton: Button = findViewById(R.id.button)
// setOnClickListner -> defines what to execute on button click
rollButton.setOnClickListener { rollDice() }
}
private fun rollDice() {
// create two dice's each with '6' sides
var dice_1 = Dice(6)
var dice_2 = Dice(6)
// roll the two dice's
val dice_1_roll = dice_1.roll()
val dice_2_roll = dice_2.roll()
// bind the obtained result to the corresponding 'textView'
val resultTextView_1: TextView = findViewById(R.id.textView)
val resultTextView_2: TextView = findViewById(R.id.textView)
// fun roll() in Dice: Class return 'Int' so convert into 'String'
resultTextView_1.text = dice_1_roll.toString()
resultTextView_2.text = dice_2_roll.toString()
}
}
class Dice(private val numSides: Int) {
fun roll(): Int {
return (1..numSides).random()
}
}
package com.example.diceroller
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Button
import android.widget.TextView
/**
* This activity allows the user to roll a dice and view the result
* on the screen.
*/
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val rollButton: Button = findViewById(R.id.button)
rollButton.setOnClickListener { rollDice() }
}
/**
* Roll the dice and update the screen with the result.
*/
private fun rollDice() {
// Create new Dice object with 6 sides and roll it
val myFirstDice = Dice(6)
val diceRollFirst = myFirstDice.roll()
// Update the screen with the dice roll
val resultTextView: TextView = findViewById(R.id.textView)
resultTextView.text = diceRollFirst.toString()
val mySecondDice = Dice(6)
val diceRollSecond = mySecondDice.roll()
val resultTextView2: TextView = findViewById(R.id.textView2)
resultTextView2.text = diceRollSecond.toString()
}
class Dice(private val numSides: Int) {
fun roll(): Int {
return (1..numSides).random()
}
}
}
kotlin android studio Unable to figure out how to covert that text to double. Can somebody correct the code please?
that code gives an error -
Unresolved reference. None of the following candidates is applicable because of receiver type mismatch:
public inline fun String.toDouble(): Double defined in kotlin.text
package com.example.termoparacalculator
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import
com.example.termoparacalculator.databinding.ActivityMainBinding
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
binding.button.setOnClickListener{
val inp = binding.input.text.toDouble()
val temp = 2.0609 * inp + 25.748
binding.textView2.text = temp
}
}
}
Assuming input is an EditText you need to do toString first
binding.input.text.toString().toDouble()
then make temp a string too when setting since its a double
binding.textView2.text = temp.toString()
This is my MainActivity.kt code
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val rollButton : Button= findViewById(R.id.roll_button)
rollButton.setOnClickListener {
rollDice()
}
}
private fun rollDice() {
val resultText: TextView = findViewById(R.id.result_text)
val randomInt = Random().nextInt(6) + 1
resultText.text = randomInt.toString()
}
}
In this code, this is the error
Cannot create an instance of an abstract class
This error is for Random() I also imported import kotlin.random.Random
If someone could please help me?
Kotlin random is
Random
So Random.nextInt() will fix it.
If you go to the import and then click ctrl+b or cmd+b it will take you to the Random file. Scroll down and you will find the companion object, there all of the methods are exposed for simplicity. So you are basically saying Random file dot use the companion object method nextInt()
https://stackoverflow.com/a/60124584/10012330 <-- check here
If you want to use the Kotlin Random class then use like this. with below import.
import kotlin.random.Random
val random = Random(12)
I want to move from one Activity which displays a RecyclerView to another Activity (detail). But when I added data transmission via Intent, the data always failed to be taken in the Activity detail.
This is the error:
My MainDetail:
private lateinit var viewModel: MainDetailModel
var idAnime: String = "34134"
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main_detail)
idAnime = intent.getStringExtra("idAnime")
println("idanime $idAnime")
setupFragment()
setupViewModel()
}
}
ViewModel:
class MainViewModel(context: Application, private val appRepository: AppRepository, private val contexts: Context) : AndroidViewModel(context), MainItemClickAction {
override fun onItemClicked(detailModel: DetailModel) {
var intent = Intent(contexts, MainDetailActivity::class.java)
intent.putExtra("idAnime",detailModel.mal_id )
contexts.startActivity(intent)
}
}
Check if your field "detailModel.mal_id" mal_id in that case is string, because you're requesting string in details activity. If it's string check also if this "mal_id" is null. Other issues from code you provided can't be seen.
Check your value idAnime, it exists or not, I think is better check all value is empty or not before putting into listView or another view.