Android App Development: Java Classes That Must (and Must Not) Be Extended

By Barry Burd

If a Java class isn’t broken, don’t fix it. Suppose you want to add functionality to an existing Java class. You like Android’s Activity class, but the pre-declared Activity class displays nothing on the screen. Do you rewrite Android’s Activity class? No.

Instead of rewriting an existing class, you extend the class. Even in a do-nothing Android “Hello” application, you write

public class MyActivity extends Activity

Then, in the MyActivity class’s declaration, you write

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}

Your MyActivity class creates new functionality by extending most of Android’s Activity functionality while overriding the Activity class’s brain-dead onCreate method.

Java’s final classes

In object-oriented programming, extending a class is the noblest thing you can do.

But some classes aren’t meant to be extended. Take, for example, Java’s String class. A String is a String is a String. You don’t want somebody’s MyString.length method to return the length of time it takes to scramble a string’s characters. To prevent someone from doing something unexpected, unconventional, or unusual with a string’s methods, the creators of Java made the String class final:

public final class String

Some of Android’s pre-declared classes are also final, including the Telephony and MediaStore classes.

Java’s abstract classes

Just as a final class hates to be extended, an abstract class insists on being extended. Android’s ViewGroup is an example of an abstract class.

public abstract class ViewGroup {
public void bringChildToFront(View child) {
int index = indexOfChild(child);
if (index >= 0) {
removeFromArray(index);
addInArray(child, mChildrenCount);
child.mParent = this;
}
}
protected abstract void onLayout(boolean changed,
int l, int t, int r, int b);
}

Android’s ViewGroup.java file is more than 3,700 lines long. So this example has only a tiny fraction of the file’s code. But you can see how a class becomes abstract. To no one’s surprise, the word abstract precedes the word class. But the word abstract also starts the declaration of some methods belonging to the class.

The founders of Android decided that the idea of a ViewGroup is useful. They were correct because your favorite Android layouts (LinearLayout, RelativeLayout, and so on) are subclasses of ViewGroup. They also understood that from one kind of ViewGroup to another, some functionality doesn’t change. For example, the example above defines a bringChildToFront method, and subclasses of ViewGroup inherit this method.

But the founders also realized that some aspects of a ViewGroup make no sense unless you work with a particular kind of group. For example, a LinearLayout positions things one after another, and a RelativeLayout positions things above, below, and to the side of one another. So the code above doesn’t have a full-blown onLayout method.

The onLayout declaration has no method body. But Android requires each subclass of the ViewGroup class to declare its own onLayout method. Java enforces this requirement when you declare method onLayout to be abstract.

As a developer, you can’t create an object from an abstract class. If you write

ViewGroup group = new ViewGroup();

Java tells you that you’re behaving badly. To do something useful with the ViewGroup class, you need a subclass of the ViewGroup class. The subclass has a concrete version of each abstract method in the ViewGroup class:

package com.allmycode.samples;
import android.content.Context;
import android.view.ViewGroup;
public class MyLayout extends ViewGroup {
public MyLayout(Context context) {
super(context);
}
@Override
protected void onLayout(boolean changed,
int l, int t, int r, int b);
}
}