Book Image

Android Design Patterns and Best Practice

By : Kyle Mew
Book Image

Android Design Patterns and Best Practice

By: Kyle Mew

Overview of this book

Are you an Android developer with some experience under your belt? Are you wondering how the experts create efficient and good-looking apps? Then your wait will end with this book! We will teach you about different Android development patterns that will enable you to write clean code and make your app stand out from the crowd. The book starts by introducing the Android development environment and exploring the support libraries. You will gradually explore the different design and layout patterns and get to know the best practices of how to use them together. Then you’ll then develop an application that will help you grasp activities, services, and broadcasts and their roles in Android development. Moving on, you will add user-detecting classes and APIs such as gesture detection, touch screen listeners, and sensors to your app. You will also learn to adapt your app to run on tablets and other devices and platforms, including Android Wear, auto, and TV. Finally, you will see how to connect your app to social media and explore deployment patterns as well as the best publishing and monetizing practices. The book will start by introducing the Android development environment and exploring the support libraries. You will gradually explore the different Design and layout patterns and learn the best practices on how to use them together. You will then develop an application that will help you grasp Activities, Services and Broadcasts and their roles in Android development. Moving on, you will add user detecting classes and APIs such as at gesture detection, touch screen listeners and sensors to our app. You will also learn to adapt your app to run on tablets and other devices and platforms, including Android Wear, Auto, and TV. Finally, you will learn to connect your app to social media and explore deployment patterns and best publishing and monetizing practices.
Table of Contents (20 chapters)
Android Design Patterns and Best Practice
Credits
About the Author
About the Reviewer
www.PacktPub.com
Customer Feedback
Preface

The abstract factory pattern


When making a sandwich, bread is only our first and most basic ingredient; we obviously need some kind of filling. In programming terms, this could mean simply building another interface like Bread but calling it Filling and providing it with its own associated factory. Equally, we could create a global interface called Ingredient and have both Bread and Filling as examples of this. Either way, we would have to do a fair bit of re-coding elsewhere.

The design pattern paradigm offers the abstract factory pattern as perhaps the most adaptable solution to this dilemma. An abstract factory is simply a factory that creates other factories. The added layer of abstraction that this requires is amply paid off when we consider how little the top-level control code in our main activity needs to be altered, if at all. Being able to modify low-level structures without affecting those preceding constitutes one of the major reasons for applying design patterns, and when applied to complex architectures, this flexibility can shave many weeks off development time and allow more room for experimentation than other approaches.

Working with more than one factory

The similarities between this next project and the last are striking, as they should be; one of the best things about patterns is that we can reuse structures. You can either edit the previous example or start one from scratch. Here, we will be starting a new project; hopefully that will help make the pattern itself clearer.

The abstract factory works in a slightly different way to our previous example. Here, our activity makes uses of a factory generator, which in turn makes use of an abstract factory class that handles the task of deciding which actual factory to call, and hence which concrete class to create.

As before we will not concern ourselves with the actual mechanics of input and output, but rather concentrate on the pattern's structure. Before continuing, start a new Android Studio project. Call it whatever you choose, set the minimum API level as low as you like, and use the Blank Activity template:

  1. We begin, just as we did before, by creating the interface; only this time, we will need two of them: one for the bread and one for the filling. They should look like this:

    public interface Bread { 
     
        String name(); 
        String calories(); 
    } 
     
    public interface Filling { 
     
        String name(); 
        String calories(); 
    } 
    
  2. As before, create concrete examples of these interfaces. Here, to save space, we will just create two of each. They are all almost identical, so here is just one:

    public class Baguette implements Bread { 
     
        @Override 
        public String name() { 
            return "Baguette"; 
        } 
     
        @Override 
        public String calories() { 
            return " : 65 kcal"; 
        } 
    } 
    
  3. Create another Bread called Brioche and two fillings called Cheese and Tomato.

  4. Next, create a class that can call on each type of factory:

    public abstract class AbstractFactory { 
     
        abstract Bread getBread(String bread); 
        abstract Filling getFilling(String filling); 
    } 
    
  5. Now create the factories themselves. First, BreadFactory:

    public class BreadFactory extends AbstractFactory { 
     
        @Override 
        Bread getBread(String bread) { 
     
            if (bread == null) { 
                return null; 
            } 
     
            if (bread == "BAG") { 
                return new Baguette(); 
            } else if (bread == "BRI") { 
                return new Brioche(); 
            } 
     
            return null; 
        } 
     
        @Override 
        Filling getFilling(String filling) { 
            return null; 
        } 
    } 
    
  6. And then, FillingFactory:

    public class FillingFactory extends AbstractFactory { 
     
        @Override 
        Filling getFilling(String filling) { 
     
            if (filling == null) { 
                return null; 
            } 
     
            if (filling == "CHE") { 
                return new Cheese(); 
            } else if (filling == "TOM") { 
                return new Tomato(); 
            } 
     
            return null; 
        } 
     
        @Override 
        Bread getBread(String bread) { 
            return null; 
        } 
    } 
    
  7. Finally, add the factory generator class itself:

    public class FactoryGenerator { 
     
        public static AbstractFactory getFactory(String factory) { 
     
            if (factory == null) { 
                return null; 
            } 
     
            if (factory == "BRE") { 
                return new BreadFactory(); 
            } else if (factory == "FIL") { 
                return new FillingFactory(); 
            } 
     
            return null; 
        } 
    } 
    
  8. We can test our code just as before, with a debug tag, like so:

    AbstractFactory fillingFactory = FactoryGenerator.getFactory("FIL"); 
    Filling filling = fillingFactory.getFilling("CHE"); 
    Log.d(DEBUG_TAG, filling.name()+" : "+filling.calories()); 
     
    AbstractFactory breadFactory = FactoryGenerator.getFactory("BRE"); 
    Bread bread = breadFactory.getBread("BRI"); 
    Log.d(DEBUG_TAG, bread.name()+" : "+bread.calories()); 
    

When tested, this should produce the following output in the Android monitor:

com.example.kyle.abstractfactory D/tag: Cheese :  : 155 kcal
com.example.kyle.abstractfactory D/tag: Brioche :  : 85 kcal

By the time we reach the end of the book, each ingredient will be a complex object in its own right, with associated imagery and descriptive text, price, calorific value, and more. This is when adhering to patterns will really pay off, but a very simple example like the one here is a great way to demonstrate how creational patterns such as the abstract factory allow us to make changes to our products without affecting client code or deployment.

As before, our understanding of the pattern can be enhanced with a visual representation:

Imagine we wanted to include soft drinks in our menu. These are neither bread nor filling, and we would need to introduce a whole new type of object. The pattern of how to add this is already laid out. We will need a new interface that would be identical to the others, only called Drink; it would utilize the same name() and calories() methods, and concrete classes such as IcedTea could be implemented along exactly the same lines as above, for example:

public class IcedTeaimplements Drink { 
 
    @Override 
    public String name() { 
        return "Iced tea"; 
    } 
 
    @Override 
    public String calories() { 
        return " : 110 kcal"; 
    } 
} 

We would need to extend our abstract factory with something like this:

abstract Drink getDrink(String drinkType); 

We also, of course, need to implement a DrinkFactory class, but this too would have the same structure as the other factories.

In other words, we can add, delete, change, and generally muck around with the nuts and bolts of a project, without ever really having to bother with how these changes are perceived by the higher-level logic of our software.

The factory pattern is one of the most frequently used of all patterns. It can and should be used in many situations. However, like all patterns, it can be overused or underused, if not thought about carefully. When considering the overall architecture of a project, there are, as we shall see, many other patterns at our disposal.