Inheritance in Android: Reuse and Extend Your Code

Inheritance in Android: Reuse and Extend Your Code

In the world of Object-Oriented Programming (OOP), inheritance is a fundamental concept that enables developers to create reusable and extendable code. Inheritance allows a class to inherit properties and methods from another class, promoting code reuse and establishing a natural hierarchy. This is particularly useful in Android development, where you often need to create complex applications with shared functionality. In this blog, we’ll explore the concept of inheritance in Android, discuss its benefits, and provide practical examples to help you understand how to implement it effectively.

What is Inheritance?

Inheritance is a mechanism in OOP that allows one class to inherit fields and methods from another class. The class that inherits is called a subclass or derived class, and the class from which it inherits is called a superclass or base class. Inheritance promotes code reuse, reduces redundancy, and makes it easier to maintain and extend applications.

Key Terms in Inheritance

  • Superclass: The class being inherited from. It provides common attributes and behaviors that can be shared with its subclasses. For example, a Vehicle class might be a superclass for Car and Bike classes.

  • Subclass: The class that inherits from the superclass. It extends the functionality of the superclass and can override its methods to provide specific behavior. For instance, a Car class might inherit from the Vehicle class and add properties like numberOfDoors.

  • extends Keyword: In Java, the extends keyword is used to indicate that a class is inheriting from another class.

Benefits of Using Inheritance

Inheritance offers several benefits that make it a powerful tool in Android development:

  • Code Reusability: By inheriting common code from a superclass, you avoid duplicating code in multiple classes. This reduces redundancy and makes your codebase cleaner.

  • Extensibility: Subclasses can extend or modify the behavior of the superclass without altering its code. This makes it easy to add new functionality and adapt existing code.

  • Maintainability: Changes in the superclass automatically propagate to its subclasses, simplifying code maintenance and updates.

  • Polymorphism: Inheritance enables polymorphism, where objects of different subclasses can be treated as objects of the superclass, allowing for flexible and interchangeable code.

Inheritance in Android Development

In Android development, inheritance is commonly used to create a hierarchy of components and to extend existing classes with additional functionality. Here are some practical examples to illustrate how inheritance is applied in Android.

Example 1: Creating a Custom View by Extending an Existing View

One of the most common uses of inheritance in Android is to create custom views by extending existing view classes. Suppose you want to create a custom button with specific behavior. You can extend the Button class to create a CustomButton class.

import android.content.Context;
import android.graphics.Color;
import android.util.AttributeSet;
import android.widget.Button;
import android.widget.Toast;

public class CustomButton extends Button {

    public CustomButton(Context context) {
        super(context);
        init();
    }

    public CustomButton(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public CustomButton(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
        // Set default properties
        this.setText("Custom Button");
        this.setBackgroundColor(Color.BLUE);

        // Set OnClickListener
        this.setOnClickListener(v ->
            Toast.makeText(getContext(), "Custom Button Clicked!", Toast.LENGTH_SHORT).show()
        );
    }
}

In this example:

  • The CustomButton class extends the Button class.

  • It overrides the constructors and calls the init method to set default properties and behaviors.

Example 2: Extending Activity to Create a Base Activity

In larger Android applications, you might have several activities that share common functionality, such as setting up a toolbar or handling permissions. You can create a BaseActivity class that extends AppCompatActivity and contains the shared functionality.

import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;

public class BaseActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_base);

        Toolbar toolbar = findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
    }

    protected void showToast(String message) {
        Toast.makeText(this, message, Toast.LENGTH_SHORT).show();
    }
}

You can then extend the BaseActivity class in your other activities to reuse the common functionality:

import android.os.Bundle;

public class MainActivity extends BaseActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // Call the showToast method from BaseActivity
        showToast("MainActivity created!");
    }
}

Example 3: Creating a Custom Adapter by Extending BaseAdapter

In Android, you often need to create custom adapters for displaying data in views like ListView or GridView. You can create a custom adapter by extending the BaseAdapter class.

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;
import java.util.List;

public class CustomAdapter extends BaseAdapter {

    private Context context;
    private List<String> data;

    public CustomAdapter(Context context, List<String> data) {
        this.context = context;
        this.data = data;
    }

    @Override
    public int getCount() {
        return data.size();
    }

    @Override
    public Object getItem(int position) {
        return data.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        if (convertView == null) {
            convertView = LayoutInflater.from(context).inflate(R.layout.list_item, parent, false);
        }

        TextView textView = convertView.findViewById(R.id.textView);
        textView.setText(data.get(position));

        return convertView;
    }
}

In this example:

  • The CustomAdapter class extends the BaseAdapter class.

  • It overrides methods to provide custom functionality for displaying data in a ListView.

Best Practices for Using Inheritance in Android

While inheritance is a powerful tool, it's important to use it judiciously to avoid potential pitfalls such as the fragile base class problem and tight coupling. Here are some best practices for using inheritance in Android development:

  • Favor Composition Over Inheritance: Prefer composition over inheritance where possible. Use inheritance to model “is-a” relationships and composition for “has-a” relationships. For example, a Car is a Vehicle, so inheritance is appropriate. However, a Car has an Engine, so composition is better suited.

  • Use Interfaces for Shared Behavior: When multiple classes need to implement shared behavior, consider using interfaces instead of inheritance. This promotes flexibility and reduces tight coupling.

  • Keep Superclasses General: Superclasses should be general and not include too many specific details that might not apply to all subclasses. This helps keep the inheritance hierarchy clean and maintainable.

  • Avoid Deep Inheritance Hierarchies: Deep inheritance hierarchies can be difficult to manage and understand. Aim for shallow hierarchies where possible.

Conclusion

Inheritance is a fundamental concept in Object-Oriented Programming that allows developers to create reusable and extendable code. In Android development, inheritance enables you to extend existing classes, create custom components, and reuse common functionality across multiple parts of your application. By following best practices and understanding how to effectively implement inheritance, you can build robust and maintainable Android apps that are easier to develop and evolve over time.