Chapter 3: Java - Part 21
So, we know that despite our efforts, somewhere in our code, we forgot to change tipPercentValue back to a percent after we changed it into a whole number. We also know that it appears related to the tipPercent EditText. Let's investigate with those things in mind.
We're going to learn a new method for this. Add a line under the line in onProgressChanged that divides tipPercentValue by 100, such that it looks like this:

tipPercentValue = tipPercentValue / 100;


The new method is System.out.println. The System.out.println method prints a line in green text in the LogCat (the ln stands for line). Note that we don't have to import anything for this method, because it is one of the special default methods Java has that is implicitly imported into every Java class. Here, every time the computer gets to this line, it will print WE HAVE ADJUSTED THE TIP PROPERLY. in the LogCat. This will help tremendously with debugging, as we will soon see. We now have a very visual way of seeing every time we divide the tip by 100.
Now go to the onFocusChange method, and find the part where we set the progress of tipSlider. Make it look like this:

System.out.println("WE'RE ABOUT TO CHANGE THE TIP.");

tipSlider.setProgress((int) tipPercentValue);

System.out.println("WE HAVE CHANGED THE TIP.");

Here, we're printing a message right before and right after we set the progress. Keep in mind the flow of the code. The computer will print the line that says WE'RE ABOUT TO CHANGE THE TIP., then set the progress, then go through all the code in onProgressChanged. Within onProgressChanged, the computer will presumably get to the code that divides the tip by 100, then print the message to confirm it, finish the onProgressChanged code, and finally print out the last message, WE HAVE CHANGED THE TIP. Thus, in the LogCat, we should see 3 messages in rapid succession that confirm everything is working as intended. If we don't we'll have a pretty good idea of what, or at least where, the problem is. Test the app. Change the first customer's first order to any number, then edit the tip to any number using the tipPercent EditText. Click out of tipPercent, then click back in and edit the tip again. Then click out again, then back in, and edit the tip one more time, then click out. Finally, click in, do not edit the tip this time, and simply click out without changing anything. To finish, click the first customer's first order EditText again, then click out of it. Again, you'll notice the buggy tip calculation at this point. Let's look at the LogCat.
You can ignore the stuff about skipping frames. That's for apps with animations, and even then, often has more to do with how slow virtual devices are than with any problems in the code. Right then, the first 3 times onFocusChange ran for tipPercent, everything went fine. We got our 3 messages, as expected. The next two times also went off without a hitch. The fourth time, we didn't bother changing the Text of tipPercent, and when onFocusChange ran for that one, we only got 2 of the 3 messages. We're missing the second message, which is the one that comes right after the line in onProgressChanged that divides tipPercentValue by 100. In other words, we're missing the message that confirms we set tipPercentValue back to a percentage number. Now let's think. Why did we not get that message when we didn't change tipPercent? Well, since we didn't get that message, we know that the computer never got to that line in the code. The computer should get to that line in the code, as long as it runs onProgressChanged. Therefore, perhaps the computer didn't run onProgressChanged that fourth time? Aha! Now we're getting somewhere. But why wouldn't the computer run onProgressChanged? Because if we don't change the value in tipPercent, then we never change the progress of tipSlider. And if we never change the progress of tipSlider, then onProgressChanged is never called! (Okay, real bug testing is a lot harder, since you don't have someone telling you all the answers, and you have to connect the dots on your own.)
Let's say tipPercent has a value of 15%. The user goes in with the intention of changing it, but then decides not to, and leaves it at 15%. Then he clicks out of tipPercent. This triggers onFocusChange. onFocusChange sets tipPercentValue to whatever is in tipPercent. Since 15 is in tipPercent, and not .15, tipPercentValue gets set to a whole number. Normally, this isn't a problem. This is because, normally, the setProgress method at the end of tipPercent's onFocusChange block will set the progress of tipSlider to a new value. This will trigger onProgressChanged, and within onProgressChanged, we have a line that reverts tipPercentValue back to percentage format by dividing it by 100. The problem occurs because when the user clicks out of tipPercent without changing the tip, setProgress will set the progress of tipSlider to what it already was. In this case, since tipSlider's progress did not change, onProgressChanged is not triggered. As a result, we never get to the line that divides tipPercentValue by 100. Bam!! Mystery solved! And of course, here's an infographic to help you out some more, if you need it.
Awesome. Okay, now that we know what's going on, let's fix the problem. In the onFocusChange block for tipPercent, under setProgress, add these lines:

if (tipPercentValue > 0.5) {

tipPercentValue = tipPercentValue / 100;


After setting the progress, tipPercentValue should be between 0 and 0.5. If it isn't, then that means onProgressChanged was never called. Thus, if tipPercentValue is bigger than 0.5, we need to divide it by 100. Great, bug squashed. You can delete the System.out.println lines now, if you want. Go ahead and test again, and you should notice that the bug is gone. More importantly, we learned how to use a valuable debugging tool.
System.out.println(data d): The System.out.println method prints out what it's passed as an argument in the LogCat. It's useful for debugging.