The Pool Class Because Reuse is Good for

What's the worst thing that can happen to us as Android developers? World-stopping garbage collection! If you look at the Input interface definition in Chapter 3, you'll find the methods getTouchEvents() and getKeyEvents(). These return lists of TouchEvents and KeyEvents. In our keyboard and touch event handlers, we'll constantly create instances of these two classes and store them in lists internal to the handlers. The Android input system fires a lot of those events when a key is pressed or a finger is touching the screen, so we'd constantly create new instances that will get collected by the garbage collector in short intervals. In order to avoid this, we will implement a concept known as instance pooling. Instead of creating new instances of a class frequently, we'll simply reuse previously created instances. The Pool class is a convenient way to implement that behavior. Let's have a look at its code in Listing 5-6.

Listing 5-6. Pool.java; Playing Well with the Garbage Collector package com.badlogic.androidgames.framework;

import java.util.ArrayList; import java.util.List;

public class Pool<T> {

Here come generics: the first thing to recognize is that this class is a generically typed class, much like collection classes, such as ArrayList or HashMap. Generics allow us to store any type of object in our Pool without having to cast like mad. So what does the Pool class do?

public interface PoolObjectFactory<T> { public T createObject();

The first thing that's defined is an interface called PoolObjectFactory, which is again generic. It has a single method, createObject(), which will return a shiny new object that has the generic type of the Pool/PoolObjectFactory instance.

private final List<T> freeObjects; private final PoolObjectFactory<T> factory; private final int maxSize;

The Pool class has three members: an ArrayList to store pooled objects, a PoolObjectFactory that is used to generate new instances of the type the class holds, and a member that stores the maximum number of objects the Pool can hold. The last bit is needed so that our Pool does not grow indefinitely; otherwise we might run into an out-of-memory exception.

public Pool(PoolObjectFactory<T> factory, int maxSize) { this.factory = factory; this.maxSize = maxSize;

this.freeObjects = new ArrayList<T>(maxSize);

The constructor of the Pool class takes a PoolObjectFactory and the maximum number of objects it should store. We store both parameters in the respective members and instantiate a new ArrayList with the capacity set to the maximum number of objects.

object = factory.createObject();

else object = freeObjects.remove(freeObjects.size() - 1); return object;

The newObject() method is responsible for either handing us a brand-new instance of the type that the Pool holds via the PoolObjectFactory.newObject() method, or returning a pooled instance in case there's one in the freeObjects ArrayList. If we use this method, we'll get recycled objects as long as the Pool has some stored in the freeObjects list. Otherwise the method will create a new one via the factory.

public void free(T object) {

if (freeObjects.size() < maxSize) freeObjects.add(object);

The free() method lets us reinsert objects we no longer use. All it does is insert the object into the freeObjects list if it is not filled to capacity yet. If the list is full, the object is not added, and is likely to be consumed by the garbage collector the next time it executes.

So how can we use that class? Let's look at some pseudocode usage of the Pool class in conjunction with touch events:

PoolObjectFactory<TouchEvent> factory = new PoolObjectFactory<TouchEvent>() { ^Override public TouchEvent createObject() { return new TouchEvent();

Pool<TouchEvent> touchEventPool = new Pool<TouchEvent>(factory, 50); TouchEvent touchEvent = touchEventPool.newObject(); ... do something here ... touchEventPool.free(touchEvent);

We first define a PoolObjectFactory that creates TouchEvent instances. Next we instantiate the Pool, telling it to use our factory and that it should maximally store 50 TouchEvents. When we want a new TouchEvent from the Pool, we call the Pool's newObject() method. Initially the Pool is empty, so it will ask the factory to create a brand-new TouchEvent instance. When we no longer need the TouchEvent, we can reinsert it into the Pool by calling the Pool's free() method. The next time we call the newObject() method, we will get the same TouchEvent instance again, recycling it so the garbage collector doesn't get mad at us. That class will come in handy in a couple of places. Just note that you have to take care if you reuse objects: it's easy to not fully reinitialize them when they're fetched from the Pool.

0 0

Responses

  • astolfo
    What is toucheventpool?
    7 years ago

Post a comment