嘿所有,这对我来说是一个非常复杂的问题,我现在一直想弄清楚。即使解释它对我来说有点困难,但我会试一试。
我正在使用Snake Android示例的内脏版本。我几乎是逐字使用TileView类,我只是试图在屏幕上显示几个图块。而不是SnakeView类我使用的是GameView类,其中我只包含了我认为在屏幕上显示图块所需的代码。这是班级
public class GameView extends TileView {
/**
* Labels for the drawables that will be loaded into the TileView class
*/
private static final int RED_STAR = 1;
private static final int YELLOW_STAR = 2;
private static final int GREEN_STAR = 3;
/**
* mMoveDelay: number of milliseconds between animations.
*/
private long mMoveDelay = 600;
/**
* mLastMove: tracks the absolute time when the last animation happened.
*/
private long mLastMove;
/**
* Create a simple handler that we can use to cause animation to happen. We
* set ourselves as a target and we can use the sleep()
* function to cause an update/invalidate to occur at a later date.
*/
private RefreshHandler mRedrawHandler = new RefreshHandler();
class RefreshHandler extends Handler {
@Override
public void handleMessage(Message msg) {
GameView.this.update();
GameView.this.invalidate();
}
public void sleep(long delayMillis) {
this.removeMessages(0);
sendMessageDelayed(obtainMessage(0), delayMillis);
}
};
/**
* Constructs a GameView based on inflation from XML
*
* @param context
* @param attrs
*/
public GameView(Context context, AttributeSet attrs) {
super(context, attrs);
initGameView();
}
public GameView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
initGameView();
}
private void initGameView() {
setFocusable(true);
Resources r = this.getContext().getResources();
resetTiles(4);
loadTile(RED_STAR, r.getDrawable(R.drawable.redstar));
loadTile(YELLOW_STAR, r.getDrawable(R.drawable.yellowstar));
loadTile(GREEN_STAR, r.getDrawable(R.drawable.greenstar));
}
public void initNewGame() {
// set the move delay. This tells the update method how often it should
// refresh the screen.
mMoveDelay = 600;
update();
}
public void update() {
long now = System.currentTimeMillis();
if (now - mLastMove > mMoveDelay) {
// clear any tiles on the screen
clearTiles();
updateWalls();
// draws the tiles storred in mCellularArray
//updateCellularArray();
mLastMove = now;
}
mRedrawHandler.sleep(mMoveDelay);
}
private void updateWalls() {
for (int x = 0; x < mXTileCount; x++) {
setTile(GREEN_STAR, x, 0);
setTile(GREEN_STAR, x, mYTileCount - 1);
}
for (int y = 1; y < mYTileCount - 1; y++) {
setTile(GREEN_STAR, 0, y);
setTile(GREEN_STAR, mXTileCount - 1, y);
}
}
private void updateCellularArray() {
setTile(YELLOW_STAR, 6, 7);
}
}
现在发生的事情是,当调用updateWalls()方法时,tile被放置在View中并且出现如下:
现在,当我取消注释updateCellularArray()
方法并注释掉updateWalls()
程序强制关闭并抛出NullPointerException时。经过一些调试后,我发现当调用updateCellular数组方法时,TileView类中的mTileGrid数组没有被初始化,而是在调用updateWalls()
时。我完全不知道为什么会这样。如果我用简单的setTile(GREEN_STAR, 3, 3);
替换for循环,它仍然会强制关闭。
这是我正在使用的TileView类(同样,这与Android SDK附带的Snake示例中的相同):
/**
* TileView: a View-variant designed for handling arrays of "icons" or other
* drawables.
*
*/
public class TileView extends View {
/**
* Parameters controlling the size of the tiles and their range within view.
* Width/Height are in pixels, and Drawables will be scaled to fit to these
* dimensions. X/Y Tile Counts are the number of tiles that will be drawn.
*/
protected static int mTileSize;
protected static int mXTileCount;
protected static int mYTileCount;
private static int mXOffset;
private static int mYOffset;
/**
* A hash that maps integer handles specified by the subclasser to the
* drawable that will be used for that reference
*/
private Bitmap[] mTileArray;
/**
* A two-dimensional array of integers in which the number represents the
* index of the tile that should be drawn at that locations
*/
private int[][] mTileGrid;
private final Paint mPaint = new Paint();
public TileView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TileView);
mTileSize = a.getInt(R.styleable.TileView_tileSize, 12);
a.recycle();
}
public TileView(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TileView);
mTileSize = a.getInt(R.styleable.TileView_tileSize, 12);
a.recycle();
}
/**
* Rests the internal array of Bitmaps used for drawing tiles, and
* sets the maximum index of tiles to be inserted
*
* @param tilecount
*/
public void resetTiles(int tilecount) {
mTileArray = new Bitmap[tilecount];
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
mXTileCount = (int) Math.floor(w / mTileSize);
mYTileCount = (int) Math.floor(h / mTileSize);
mXOffset = ((w - (mTileSize * mXTileCount)) / 2);
mYOffset = ((h - (mTileSize * mYTileCount)) / 2);
Log.d("Tomek", "TileGrid array dimensions are: " + mXTileCount + "," + mYTileCount);
mTileGrid = new int[mXTileCount][mYTileCount];
clearTiles();
}
/**
* Function to set the specified Drawable as the tile for a particular
* integer key.
*
* @param key
* @param tile
*/
public void loadTile(int key, Drawable tile) {
Bitmap bitmap = Bitmap.createBitmap(mTileSize, mTileSize, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
tile.setBounds(0, 0, mTileSize, mTileSize);
tile.draw(canvas);
mTileArray[key] = bitmap;
}
/**
* Resets all tiles to 0 (empty)
*
*/
public void clearTiles() {
for (int x = 0; x < mXTileCount; x++) {
for (int y = 0; y < mYTileCount; y++) {
setTile(0, x, y);
}
}
}
/**
* Used to indicate that a particular tile (set with loadTile and referenced
* by an integer) should be drawn at the given x/y coordinates during the
* next invalidate/draw cycle.
*
* @param tileindex
* @param x
* @param y
*/
public void setTile(int tileindex, int x, int y) {
//Log.d("Tomek", "Attempting to set tile: " + x + "," + y);
//Log.d("Tomek", "The current value at " + x + "," + y + " is " + mTileGrid[x][y]);
//Log.d("Tomek", "It will be changed to " + tileindex);
mTileGrid[x][y] = tileindex;
}
@Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
for (int x = 0; x < mXTileCount; x += 1) {
for (int y = 0; y < mYTileCount; y += 1) {
if (mTileGrid[x][y] > 0) {
canvas.drawBitmap(mTileArray[mTileGrid[x][y]],
mXOffset + x * mTileSize,
mYOffset + y * mTileSize,
mPaint);
}
}
}
}
}
很抱歉发布所有这些代码。任何帮助将不胜感激。
非常感谢,
托梅克
编辑:简化的GameView类
编辑2:将updateCellularArray()
方法修改为以下内容后正好:
private void updateCellularArray() {
for (int x = 0; x < mXTileCount; x++) {
setTile(GREEN_STAR, 12, 12);
}
}
它最终把瓷砖放在我想要的地方...... alt text http://img188.imageshack.us/img188/1148/device2z.png
我开始怀疑它是否与RefreshHandler有关。可能是在GameView类的update方法中调用RedrawHandler的sleep方法时。我不太确定它是如何工作的,所以我会试着玩它,看看我能想出什么。
答案 0 :(得分:1)
我忘了实例化mLastMove变量。将声明修改为:
private long mLastMove = System.currentTimeMillis();
修复了问题。
似乎与RefreshHandler一起使用的方法虽然很聪明,但已经过时了?发现这篇文章:
http://www.mail-archive.com/android-beginners@googlegroups.com/msg07352.html
托梅克