I just started learning Kotlin and I don't know to use when properly. When number is 1, the toast is there, but the image (the second 1 case) is not changed. Is there a way to do this with when?
when (number){
1 -> Toast.makeText(applicationContext,"1",Toast.LENGTH_SHORT).show()
1 -> imgview.setImageResource(R.drawable.dice_1)
2 -> Toast.makeText(applicationContext,"SAD",Toast.LENGTH_SHORT).show()
2 -> imgview.setImageResource(R.drawable.dice_2)
}
Sure, just wrap each set of statements in curly braces:
when (number){
1 -> {
Toast.makeText(applicationContext,"1",Toast.LENGTH_SHORT).show()
imgview.setImageResource(R.drawable.dice_1)
}
2 -> {
Toast.makeText(applicationContext,"SAD",Toast.LENGTH_SHORT).show()
imgview.setImageResource(R.drawable.dice_2)
}
}
when statement in Kotlin is similar to switch statement in Java. As soon as a matching case is found in the when statement, the control returns from the statement.
So in your code, the first 1 case gets executed and the control returns from the statement so it never goes to the second 1 case. I don't know your purpose for duplicating these cases instead of grouping them as shown in the below code:
when (number){
1 -> {
Toast.makeText(applicationContext,"1",Toast.LENGTH_SHORT).show()
imgview.setImageResource(R.drawable.dice_1)
}
2 -> {
Toast.makeText(applicationContext,"SAD",Toast.LENGTH_SHORT).show()
imgview.setImageResource(R.drawable.dice_2)
}
}
when (number){
1 -> {
Toast.makeText(applicationContext,"1",Toast.LENGTH_SHORT).show()
imgview.setImageResource(R.drawable.dice_1)}
2 ->{ Toast.makeText(applicationContext,"SAD",Toast.LENGTH_SHORT).show()
imgview.setImageResource(R.drawable.dice_2) }
else->{
//if both fail to mach
}
}
Add curly braces to define scope.
when looks for the first condition that matches, so once you hit the first 1 branch, it executes the code and then exits the block. It doesn't fall through to the others - you can think of it like a big if/else if/else if/else block, where the later ones can only trigger if nothing before them did.
So you need to execute all your code in the first branch that matches, like the other answers are showing!
Related
In android studio using kotlin, I created a class with the code below:
class Dice(val numSides:Int){
fun roll():Int{
return (1..numSides).random()
}
}
in ExampleUnitTest.kt file I have created the following code to test:
class ExampleUnitTest {
#Test
fun generates_number() {
val dice = Dice(4)
val rollResult = dice.roll()
assertTrue("The value of rollResult was not between 1 and 6", rollResult in 1..6)
}
}
The test should be passed only if Dice(6) as the result should be any number between 1 to 6 but as shown above when with Dice(4) or any number, the test passed. that why? thanks
Your test checks if the rolled number is between 1 and 6. With Dice(4) the result will be between 1 and 4, which means it's always going to be between 1 and 6 as well. Or to put it another way, it's impossible for you to get a value from Dice(4).roll() that isn't somewhere between 1 and 6 - it's never going to be 5 or 6, but that doesn't contradict anything!
What you probably want to test is whether Dice(4).roll()'s possible range of outputs is from 1 to 6. But there's no way to absolutely prove that from the outside, not the way the class is written anyway. All you can do is provide a value for numSides and then call roll() and check the output. That's all the class offers to you in terms of interactivity.
A better question is why you want to test this? Your test seems to be written to fail when your code is working - you should be testing that the behaviour is what you'd expect, so all your tests pass. So really, what you'd want to test is that Dice(4).roll() only produces values within the expected range, i.e. between 1 and 4.
Since it's random the only way to really do this is run the same test lots of times and make sure a bad number never comes up (or you eventually see a number you want), so you can say with a high degree of confidence that it's probably correct. Something like
#Test
fun generates_number() {
val dice = Dice(4)
val allGood = generateSequence { dice.roll() }.take(9999).all { it in 1..4 }
assertTrue("At least one dice roll was not between 1 and 4", allGood)
}
(or you could use a for loop with break to exit early if one of the values isn't valid, instead of the sequence + all)
I just picked 9999 at random but you could use statistics to pick a more suitable number. But the problem here is the random behaviour - because it's not predictable, you can't do a simple state in -> result out test with an expected result.
i am new to Android development with Kotlin pogramming language, i am not able to understand this code below,
what i am guessing is that an instance(scanResultAdapter) is created from ScanResultAdapter class, this class has the code for recyclerView adapter.
This code is in MainActivity.kt file in punchThrough's article about BLE -
private val scanResultAdapter: ScanResultAdapter by lazy {
ScanResultAdapter(scanResults) { result ->
// User tapped on a scan result
if (isScanning) {
stopBleScan()
}
with(result.device) {
Log.w("ScanResultAdapter", "Connecting to $address")
connectGatt(context, false, gattCallback)
}
}
}
Which point you don't understand?
Regards your guess(the logic of code), that's right, I think.
It seems that you are not familiar with Kotlin, you can check them one by one. For an instance, I don't know this style code:
ScanResultAdapter(scanResults) { result ->
....
}
{ result -> .. }, I need to know that's the Lambdas Expressions
Here's a reference
Maybe I don't understand the with of Kotlin, refer to this document and so on.
You are right. (scanResults) is the first argument of constructor. Second is callback of click listener in curly brackets. When user tap on a device in the list this code in braces {} will be executed. Kotlin can take out of parentheses () arguments if it is functions.
I am using Kotlin language and I have Bottom Navigation View in my app. I want to implement setOnNavigationItemSelectedListener method for changing the my viewPager.
However when I implement it gives me error which is 'change lambda expression return type to Unit' . I don't understand why. I checked on internet, some people use same lines code with me but they don't get error. I will share screenshot of error.
Also when I change setOnNavigationItemSelectedListener to etOnNavigationItemReselectedListener it doesn't give error. However I need to selectItemListener not Reselect .
This is my method.
Add true in your lambda, right after the when statement. This functional interface requires you to return a Boolean value. The last expression of a lambda is the return value.
For less repetitive code, you may consider modifying it as shown:
bottomNavigationView.setOnNavigationItemSelectedListener {
val page = when (it.itemId) {
R.id.navigator_main -> 0
R.id.navigator_search_food -> 1
R.id.navigator_list_of_week -> 2
R.id.navigator_for_students -> 3
else -> -1
}
viewPager.setCurrentItem(page)
true
}
I am struggling with one RxJava use case and could use some assistant.
When a button is clicked I open a dialog to let user pick a value. Dialog needs initial value which is equal to previousely chosen value (or default one). I try to implement it like this:
Observables.combineLatest(
RxView.clicks(my_button),
viewModel.valueObservable
)
.subscribe { clickAndValuePair->
showDialog(
initialValue = clickAndValuePair.second
)
}
The problem is, when new value is picked the dialog is opened again, because new value is emitted in this combined Observable. What is the best practice to handle such situation?
You might be able to handle this with the zip() operator:
Observables.zip(
RxView.clicks(my_button),
viewModel.valueObservable
).subscribe {
showDialog(initialValue = it.second)
}
The zip operation matches every n-th item of the observables together, thus it always waits for a click after emitting. For this you need to make sure to only update the value from the dialog and always update it from there. Even if you have not updated anything.
A better alternative might be to just get the latest value whenever there was a click with the withLatestFrom() operator:
RxView.clicks(my_button)
.withLatestFrom(viewModel.valueObservable)
.subscribe { showDialog(initialValue = it.second)}
The Code A is good, I hope to optimize it, so I write the Code B.
I'm not sure whether the Code B is always correct.
It will be OK if Kotlin check clipboard.hasPrimaryClip() first, then check clipboard.primaryClipDescription.hasMimeType(MIMETYPE_TEXT_PLAIN) next.
It maybe crash if Kotlin check clipboard.primaryClipDescription.hasMimeType(MIMETYPE_TEXT_PLAIN) first, the check clipboard.hasPrimaryClip() next, right?
Code A
clipboard.addPrimaryClipChangedListener {
if (clipboard.hasPrimaryClip() ) {
if (clipboard.primaryClipDescription.hasMimeType(MIMETYPE_TEXT_PLAIN)) {
}
}
}
Code B
clipboard.addPrimaryClipChangedListener {
if (clipboard.hasPrimaryClip() && clipboard.primaryClipDescription.hasMimeType(MIMETYPE_TEXT_PLAIN) ) {
}
}
if conditions run sequentially. That means it will first check the left condition and if the operator is AND and left condition return false then it won't check the right condition. So yes, you can merge two conditions.
As mentioned in the comments, the principle behind this is described as "short circuiting":
Short-circuit evaluation [...] is the semantics of some Boolean operators in some programming languages in which the second argument is executed or evaluated only if the first argument does not suffice to determine the value of the expression.
That means clipboard.hasPrimaryClip() will always be evaluated. If it's false
, the condition fails without looking any further. If it is true though, clipboard.primaryClipDescription.hasMimeType(MIMETYPE_TEXT_PLAIN) will be evaluated as well.