您的位置:首页 > 移动开发 > Android开发

Android游戏开发框架(三)垃圾回收器

2013-02-10 23:35 106 查看
以下均转自Android游戏编程入门经典,转载请标明出处


对于Android开发人员来说,什么是最糟糕的事情?让一切工作都停止运行的垃圾回收!

我们先来看看Input接口

package org.example.androidgames.framework;

import java.util.List;

public interface Input {
    public static class KeyEvent {
        public static final int KEY_DOWN = 0;
        public static final int KEY_UP = 1;

        public int type;
        public int keyCode;
        public char keyChar;

        public String toString() {
            StringBuilder builder = new StringBuilder();
            if (type == KEY_DOWN)
                builder.append("key down, ");
            else
                builder.append("key up, ");
            builder.append(keyCode);
            builder.append(",");
            builder.append(keyChar);
            return builder.toString();
        }
    }

    public static class TouchEvent {
        public static final int TOUCH_DOWN = 0;
        public static final int TOUCH_UP = 1;
        public static final int TOUCH_DRAGGED = 2;

        public int type;
        public int x, y;
        public int pointer;

        public String toString() {
            StringBuilder builder = new StringBuilder();
            if (type == TOUCH_DOWN)
                builder.append("touch down, ");
            else if (type == TOUCH_DRAGGED)
                builder.append("touch dragged, ");
            else
                builder.append("touch up, ");
            builder.append(pointer);
            builder.append(",");
            builder.append(x);
            builder.append(",");
            builder.append(y);
            return builder.toString();
        }
    }

    public boolean isKeyPressed(int keyCode);

    public boolean isTouchDown(int pointer);

    public int getTouchX(int pointer);

    public int getTouchY(int pointer);

    public float getAccelX();

    public float getAccelY();

    public float getAccelZ();

    public List<KeyEvent> getKeyEvents();

    public List<TouchEvent> getTouchEvents();
}


我们从定义两个类开始,KeyEvent和TouchEvent。KeyEvent类定义了一些该常量类型,TouchEvent也是一样。当事件类型为KEY_UP时,一个KeyEvent实例将会记录它的类型、按键代码和Unicode字符。

TouchEvent的代码也很相似,它定义了TouchEvent事件类型、触点相对于UI组件原点的位置和触摸屏的驱动程序赋予手指的指针ID。只要手指还在屏幕上,那么它的指针ID是不会变的。如果按下了两只手指,那么当手指0离开时,手指1会保持其ID不变直到它离开触摸屏。当一个新的手指按下时会得到第一个未占用的ID,本例中将会得到0。指针ID通常是按顺序分配的,但是并不保证一定如此。

接下来便是Input接口的轮询方法,其用途很明显。Input.isKeyPressed()接受一个keyCode参数,并返回对应当前按键是否被按下信息。Input.isTouchDown()、Input.getTouchX()和Input.getTouchY()返回是否按下一个给定的指针,以及其当前的x和y坐标。注意,如果实际上相应的指针没有触摸屏幕的话,其坐标是没法确定的。

Input.getAccelX()、Input.getAccelY()、Input.getAccelZ()返回加速计在各个轴上的值。

最后两个方法用于基于事件的处理,它将返回上次我们调用这些方法后所记录的KeyEvent和TouchEvent实例。该事件按发生时间排序,最新发生的事件排在列表的最后面。

现在回到垃圾回收器设计上来,在Input接口里getTouchEvents()和getKeyEvents()方法。它将返回TouchEvent和KeyEvent列表。在键盘和触摸事件处理程序中,我们将不断创建这两个类的实例,并将它们存储在内部处理程序的列表中。当一个键被按下或手指触摸屏幕时,Android的输入系统会触发很多事件。所以我们会不断创建新实例,在很短的时间间隔内,这些事件会被垃圾回收器收集。为了避免这种情况,我们将实现一个称之为实力入池(instance
pooling)的概念。它不是在一个类中不断地创建新实例,而是简单地重用以前的实例。Pool类是实现这种行为的一种很便捷的方式。

package org.example.androidgames.framework;

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

public class Pool<T> {
	private final List<T> freeObjects;
	private final PoolObjectFactory<T> factory;
	private final int maxSize;
	public interface PoolObjectFactory<T>{
		public T createObject();
	}
	
	public Pool(PoolObjectFactory<T> factory, int maxSize){
		this.factory = factory;
		this.maxSize = maxSize;
		this.freeObjects =new ArrayList<T>(maxSize);
	}
	
	public T newObject(){
		T object = null;
		if(freeObjects.size() == 0)
			object = factory.createObject();
		else
			object = freeObjects.remove(freeObjects.size() - 1);
		
		return object;
	}
	
	public void free(T object){
		if(freeObjects.size() < maxSize)
			freeObjects.add(object);
	}
}


Pool<T>这里使用了泛型。这个类是个通用类型的类,泛型允许我们在Pool类中存储任何类型的对象,而无须对类型进行转换。

首先定义的是一个名为PoolObjectFactory的接口,它是泛型的。它只有一个方法createObject(),该方法将返回一个新对象,其具有泛型类型的Pool/PoolObjectFactory实例。

Pool类有3个成员:ArrayList用于存储以入池的对象,PoolObjectFactory用于生成Pool类中包含的类型的新实例,第三个成员用于存放Pool可以容纳的最大对象数量。最后一个成员是必需的,这样Pool才不会无限制增长;否则,我们将可能会遇到一个内存耗尽的异常。

Pool类的构造函数接受一个PoolObjectFactory和所存储对象的最大数量。这两个参数都存储在各自的成员变量里,并且我们实例化一个新的ArrayList,其大小设为对象的最大数量。

newObject()方法负责通过PoolObjectFactory.newObject()方法给我们传递一个全新的Pool实例,或者在freeObjectsArrayList中有对象的情况下,返回一个已入池的实例。如果使用这种方法,只要Pool类中有一些对象存储在freeObjects列表中,我们将得到一些可回收的对象。否则,该方法将通过工厂类创建一个新的对象。

free()方法允许我们重新插入不再使用的对象。它的工作就是如果freeObjects列表中没有满,就将对象插入到freeObjects列表中。如果列表已满,则不再添加对象,并且对象可能在free()方法下一次执行时被垃圾回收器回收。

至于我们如果用Pool类创建一个TouchEvent实例,时候不早了,下次再写
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: