Anonymous classes

In the last chapter, we briefly introduced anonymous classes. Here, we will learn a little more about them and see how they can help us. When a RadioButton is part of a RadioGroup, the visual appearance of them all is coordinated for us. All we need to do is react when any given RadioButton is pressed. Of course, as with any other button, we need to know when they have been clicked.

A RadioButton behaves differently to a regular Button, and simply listening for clicks in onClick (after implementing OnClickListener) will not work because RadioButton is not designed that way.

What we need to do is use another Java feature. We need to implement a class, an anonymous class, for the sole purpose of listening for clicks on the RadioGroup. The following block of code assumes that we have a reference to a RadioGroup called radioGroup. Here is the code:

radioGroup.setOnCheckedChangeListener(
   new RadioGroup.OnCheckedChangeListener() {
   
         @Override
         public void onCheckedChanged(RadioGroup group, 
                int checkedId) {
                
                // Handle clicks here
         }
   }
);

The preceding code, specifically RadioGroup.OnCheckedChangeListener from its opening { to closing }, is what is known as an anonymous class because it has no name.

The actual class code does not run when onCreate is called; it simply prepares the class ready to handle any clicks on radioGroup. We will now discuss this in more detail.

Note

This class is more technically known as an anonymous inner class because it is inside another class. Inner classes can be anonymous or have names. We will see an inner class with a name in Chapter 16, Adapters and Recyclers.

I remember the first time I saw an anonymous class and it almost made me want to hide in a cupboard, but it is not as complex as it might look at first.

What we are doing is adding a listener to radioGroup, which has very much the same effect as when we implemented the View.OnClickListener in Chapter 12, The Stack, the Heap, and the Garbage Collector. Only this time, we are declaring and instantiating a listener class, and preparing it to listen to radioGroup, while simultaneously overriding the required method, which in this case is onCheckedChanged. This is like the RadioGroup equivalent of onClick.

Let's step through it. We call the setOnCheckedChangeListener method on our radioGroup as follows:

radioGroup.setOnCheckedChangeListener(

We pass in a new anonymous class, along with the details of its overridden method, as the argument, as follows:

new RadioGroup.OnCheckedChangeListener() {
      
      @Override
      public void onCheckedChanged(RadioGroup group, 
             int checkedId) {
                   
             // Handle clicks here
      }
}

Finally, we have the closing parenthesis of the method. And, of course, the semi-colon to mark the end of the line. The only reason we present it on multiple lines is to make it more readable. As far as the compiler is concerned, it could all be lumped together:

);

If we use the preceding code to create and instantiate a class that listens for clicks to our RadioGroup, perhaps in the onCreate method, it will listen and respond for the entire life of the Activity. All we need to learn now is to handle the clicks in the onCheckedChanged method that we override.

Notice that one of the parameters of this method that is passed in when the radioGroup is pressed is int checkedId. This holds the id of the currently selected RadioButton. This is just what we need – almost.

It might be surprising that checkedId is an int. Android stores all ids as int, even though we declare them with alphanumeric characters such as radioButton1 or radioGroup.

All our human-friendly names are converted to int when the app is compiled. So, how do we know which int refers to an id, such as radioButton1 or radioButton2 and so on?

What we need to do is get a reference to the actual object that the int is an id for, using the int id, and then ask the object for its human-friendly id. We would do so like this:

RadioButton rb = (RadioButton) group.findViewById(checkedId);

Now, we can retrieve the familiar id that we used for the currently selected RadioButton, for which we now have a reference stored in rb, with the getId method, as follows:

rb.getId();

We could therefore handle RadioButton clicks by using a switch block with a case for each possible RadioButton that could be pressed, and rb.getId() as the switch block's expression.

The following code shows the entire contents of the onCheckedChanged method we just discussed:

// Get a reference to the RadioButton 
// that is currently checked
RadioButton rb = (RadioButton) group.findViewById(checkedId);

// Switch based on the 'friendly' id
switch (rb.getId()) {

   case R.id.radioButton1:
          // Do something here
          break;

   case R.id.radioButton2:
          // Do something here
          break;


   case R.id.radioButton3:
          // Do something here
          break;


}
// End switch block

Seeing this in action in the next working mini-app, where we can press the buttons for real, will make this clearer.

Let's continue with our palette exploration.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.17.74.227