Android apps浅析01-Amazed:一个简单但令人上瘾的加速度为基础的大理石指导游戏。

简介: Android apps浅析01-Amazed:一个简单但令人上瘾的加速度为基础的大理石指导游戏。 这个例子中只有4个类,一个绘制大理石类Marble,一个绘制迷宫类Maze,一个Amazed视图类,一个Amazed活动类 1.

Android apps浅析01-Amazed:一个简单但令人上瘾的加速度为基础的大理石指导游戏。

 

这个例子中只有4个类,一个绘制大理石类Marble,一个绘制迷宫类Maze,一个Amazed视图类,一个Amazed活动类

 

1. 绘制大理石类Marble通过Canvas和Paint绘制,同时提供移动x轴和y轴坐标的方法,每个大理石都有一个状态值:活的/死的

/*
 * Copyright (C) 2008 Jason Tomlinson.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.example.amazed;

import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.view.View;

/**
 * Marble drawn in the maze.迷宫中的大理石绘制
 */
public class Marble {

    // View controlling the marble.
    private View mView;

    // marble attributes
    // x,y are private because we need boundary checking on any new values to
    // make sure they are valid.
    private int mX = 0;
    private int mY = 0;
    private int mRadius = 8;
    private int mColor = Color.WHITE;
    private int mLives = 5;

    /**
     * Marble constructor.
     * 
     * @param view
     *            View controlling the marble
     */
    public Marble(View view) {
        this.mView = view;
        init();
    }

    /**
     * Setup marble starting co-ords.
     */
    public void init() {
        mX = mRadius * 6;
        mY = mRadius * 6;
    }

    /**
     * Draw the marble.
     * 
     * @param canvas
     *            Canvas object to draw too.
     * @param paint
     *            Paint object used to draw with.
     */
    public void draw(Canvas canvas, Paint paint) {
        paint.setColor(mColor);
        canvas.drawCircle(mX, mY, mRadius, paint);
    }

    /**
     * Attempt to update the marble with a new x value, boundary checking
     * enabled to make sure the new co-ordinate is valid.
     * 
     * @param newX
     *            Incremental value to add onto current x co-ordinate.
     */
    public void updateX(float newX) {
        mX += newX;

        // boundary checking, don't want the marble rolling off-screen.
        if (mX + mRadius >= mView.getWidth())
            mX = mView.getWidth() - mRadius;
        else if (mX - mRadius < 0)
            mX = mRadius;
    }

    /**
     * Attempt to update the marble with a new y value, boundary checking
     * enabled to make sure the new co-ordinate is valid.
     * 
     * @param newY
     *            Incremental value to add onto current y co-ordinate.
     */
    public void updateY(float newY) {
        mY -= newY;

        // boundary checking, don't want the marble rolling off-screen.
        if (mY + mRadius >= mView.getHeight())
            mY = mView.getHeight() - mRadius;
        else if (mY - mRadius < 0)
            mY = mRadius;
    }

    /**
     * Marble has died
     */
    public void death() {
        mLives--;
    }

    /**
     * Set the number of lives for the marble
     * 
     * @param Number
     *            of lives
     */
    public void setLives(int val) {
        mLives = val;
    }

    /**
     * @return Number of lives left
     */
    public int getLives() {
        return mLives;
    }

    /**
     * @return Current x co-ordinate.
     */
    public int getX() {
        return mX;
    }

    /**
     * @return Current y co-ordinate.
     */
    public int getY() {
        return mY;
    }
}


 

2. 绘制迷宫类Maze绘制一个20列26行的长方形,提供加载背景和数据以及等级的方法,同样通过Canvas和Paint绘制,另外需要提供(x,y)坐标上的大理石数据是活的还是死的

/*
 * Copyright (C) 2008 Jason Tomlinson.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.example.amazed;

import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;

import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.Log;

/**
 * Maze drawn on screen, each new level is loaded once the previous level has
 * been completed.屏幕上迷宫绘制,一旦前一个级别完成后,每个新级别会被加载。
 */
public class Maze {
	
    // maze tile size and dimension
    private final static int TILE_SIZE = 16;
    private final static int MAZE_COLS = 20;
    private final static int MAZE_ROWS = 26;

    // tile types
    public final static int PATH_TILE = 0;
    public final static int VOID_TILE = 1;
    public final static int EXIT_TILE = 2;

    // tile colors
    private final static int VOID_COLOR = Color.BLACK;

    // maze level data
    private static int[] mMazeData;

    // number of level
    public final static int MAX_LEVELS = 10;

    // current tile attributes
    private Rect mRect = new Rect();
    private int mRow;
    private int mCol;
    private int mX;
    private int mY;

    // tile bitmaps
    private Bitmap mImgPath;
    private Bitmap mImgExit;

    /**
     * Maze constructor.
     * 
     * @param context
     *            Application context used to load images.
     */
    Maze(Activity activity) {

        // load bitmaps.
        mImgPath = BitmapFactory.decodeResource(activity.getApplicationContext().getResources(),
                R.drawable.path);
        mImgExit = BitmapFactory.decodeResource(activity.getApplicationContext().getResources(),
                R.drawable.exit);
    }

    /**
     * Load specified maze level.
     * 
     * @param activity
     *           Activity controlled the maze, we use this load the level data
     * @param newLevel
     *            Maze level to be loaded.
     */
    void load(Activity activity, int newLevel) {
        // maze data is stored in the assets folder as level1.txt, level2.txt
        // etc....
        String mLevel = "level" + newLevel + ".txt";

        InputStream is = null;

        try {
            // construct our maze data array.
            mMazeData = new int[MAZE_ROWS * MAZE_COLS];
            // attempt to load maze data.
            is = activity.getAssets().open(mLevel);

            // we need to loop through the input stream and load each tile for
            // the current maze.
            for (int i = 0; i < mMazeData.length; i++) {
                // data is stored in unicode so we need to convert it.
                mMazeData[i] = Character.getNumericValue(is.read());

                // skip the "," and white space in our human readable file.
                is.read();
                is.read();
            }
        } catch (Exception e) {
            Log.i("Maze", "load exception: " + e);
        } finally {
            closeStream(is);
        }

    }

    /**
     * Draw the maze.
     * 
     * @param canvas
     *            Canvas object to draw too.
     * @param paint
     *            Paint object used to draw with.
     */
    public void draw(Canvas canvas, Paint paint) {
        // loop through our maze and draw each tile individually.
        for (int i = 0; i < mMazeData.length; i++) {
            // calculate the row and column of the current tile.
            mRow = i / MAZE_COLS;
            mCol = i % MAZE_COLS;

            // convert the row and column into actual x,y co-ordinates so we can
            // draw it on screen.
            mX = mCol * TILE_SIZE;
            mY = mRow * TILE_SIZE;

            // draw the actual tile based on type.
            if (mMazeData[i] == PATH_TILE)
                canvas.drawBitmap(mImgPath, mX, mY, paint);
            else if (mMazeData[i] == EXIT_TILE)
                canvas.drawBitmap(mImgExit, mX, mY, paint);
            else if (mMazeData[i] == VOID_TILE) {
                // since our "void" tile is purely black lets draw a rectangle
                // instead of using an image.

                // tile attributes we are going to paint.
                mRect.left = mX;
                mRect.top = mY;
                mRect.right = mX + TILE_SIZE;
                mRect.bottom = mY + TILE_SIZE;

                paint.setColor(VOID_COLOR);
                canvas.drawRect(mRect, paint);
            }
        }

    }

    /**
     * Determine which cell the marble currently occupies.
     * 
     * @param x
     *            Current x co-ordinate.
     * @param y
     *            Current y co-ordinate.
     * @return The actual cell occupied by the marble.
     */
    public int getCellType(int x, int y) {
        // convert the x,y co-ordinate into row and col values.
        int mCellCol = x / TILE_SIZE;
        int mCellRow = y / TILE_SIZE;

        // location is the row,col coordinate converted so we know where in the
        // maze array to look.
        int mLocation = 0;

        // if we are beyond the 1st row need to multiple by the number of
        // columns.
        if (mCellRow > 0)
            mLocation = mCellRow * MAZE_COLS;

        // add the column location.
        mLocation += mCellCol;

        return mMazeData[mLocation];
    }

    /**
     * Closes the specified stream.
     * 
     * @param stream
     *            The stream to close.
     */
    private static void closeStream(Closeable stream) {
        if (stream != null) {
            try {
                stream.close();
            } catch (IOException e) {
                // Ignore
            }
        }
    }
}


 

 

3. Amazed视图类,自定义view用于绘制迷宫和大理石,响应加速度计的更新在屏幕上滚动的大理石,通过SensorListener和SensorManager传感器相关的类监听用户触摸的单元xyz坐标值,重载View的onDraw方法来调用游戏开始前,游戏开始中,游戏结束和游戏完成相应的绘制函数

/*
 * Copyright (C) 2008 Jason Tomlinson.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.example.amazed;

import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Typeface;
import android.hardware.SensorListener;
import android.hardware.SensorManager;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;

/**
 * Custom view used to draw the maze and marble. Responds to accelerometer
 * updates to roll the marble around the screen.自定义view用于绘制迷宫和大理石,响应加速度计的更新在屏幕上滚动的大理石。
 */
public class AmazedView extends View {
    // Game objects
    private Marble mMarble;
    private Maze mMaze;
    private Activity mActivity;

    // canvas we paint to.
    private Canvas mCanvas;

    private Paint mPaint;
    private Typeface mFont = Typeface.create(Typeface.SANS_SERIF, Typeface.BOLD);
    private int mTextPadding = 10;
    private int mHudTextY = 440;

    // game states
    private final static int NULL_STATE = -1;
    private final static int GAME_INIT = 0;
    private final static int GAME_RUNNING = 1;
    private final static int GAME_OVER = 2;
    private final static int GAME_COMPLETE = 3;
    private final static int GAME_LANDSCAPE = 4;
    // current state of the game
    private static int mCurState = NULL_STATE;

    // game strings
    private final static int TXT_LIVES = 0;
    private final static int TXT_LEVEL = 1;
    private final static int TXT_TIME = 2;
    private final static int TXT_TAP_SCREEN = 3;
    private final static int TXT_GAME_COMPLETE = 4;
    private final static int TXT_GAME_OVER = 5;
    private final static int TXT_TOTAL_TIME = 6;
    private final static int TXT_GAME_OVER_MSG_A = 7;
    private final static int TXT_GAME_OVER_MSG_B = 8;
    private final static int TXT_RESTART = 9;
    private final static int TXT_LANDSCAPE_MODE = 10;
    private static String mStrings[];

    // this prevents the user from dying instantly when they start a level if
    // the device is tilted.
    private boolean mWarning = false;

    // screen dimensions
    private int mCanvasWidth = 0;
    private int mCanvasHeight = 0;
    private int mCanvasHalfWidth = 0;
    private int mCanvasHalfHeight = 0;

    // are we running in portrait mode.
    private boolean mPortrait;

    // current level
    private int mlevel = 1;

    // timing used for scoring.
    private long mTotalTime = 0;
    private long mStartTime = 0;
    private long mEndTime = 0;

    // sensor manager used to control the accelerometer sensor.
    private SensorManager mSensorManager;
    // accelerometer sensor values.
    private float mAccelX = 0;
    private float mAccelY = 0;
    private float mAccelZ = 0; // this is never used but just in-case future
    // versions make use of it.

    // accelerometer buffer, currently set to 0 so even the slightest movement
    // will roll the marble.
    private float mSensorBuffer = 0;

    // http://code.google.com/android/reference/android/hardware/SensorManager.html#SENSOR_ACCELEROMETER
    // for an explanation on the values reported by SENSOR_ACCELEROMETER.
    private final SensorListener mSensorAccelerometer = new SensorListener() {

        // method called whenever new sensor values are reported.
        public void onSensorChanged(int sensor, float[] values) {
            // grab the values required to respond to user movement.
            mAccelX = values[0];
            mAccelY = values[1];
            mAccelZ = values[2];
        }

        // reports when the accuracy of sensor has change
        // SENSOR_STATUS_ACCURACY_HIGH = 3
        // SENSOR_STATUS_ACCURACY_LOW = 1
        // SENSOR_STATUS_ACCURACY_MEDIUM = 2
        // SENSOR_STATUS_UNRELIABLE = 0 //calibration required.
        public void onAccuracyChanged(int sensor, int accuracy) {
            // currently not used
        }
    };

    /**
     * Custom view constructor.
     * 
     * @param context
     *            Application context
     * @param activity
     *            Activity controlling the view
     */
    public AmazedView(Context context, Activity activity) {
        super(context);

        mActivity = activity;

        // init paint and make is look "nice" with anti-aliasing.
        mPaint = new Paint();
        mPaint.setTextSize(14);
        mPaint.setTypeface(mFont);
        mPaint.setAntiAlias(true);

        // setup accelerometer sensor manager.
        mSensorManager = (SensorManager) activity.getSystemService(Context.SENSOR_SERVICE);
        // register our accelerometer so we can receive values.
        // SENSOR_DELAY_GAME is the recommended rate for games
        mSensorManager.registerListener(mSensorAccelerometer, SensorManager.SENSOR_ACCELEROMETER,
                SensorManager.SENSOR_DELAY_GAME);

        // setup our maze and marble.
        mMaze = new Maze(mActivity);
        mMarble = new Marble(this);

        // load array from /res/values/strings.xml
        mStrings = getResources().getStringArray(R.array.gameStrings);

        // set the starting state of the game.
        switchGameState(GAME_INIT);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);

        // get new screen dimensions.
        mCanvasWidth = w;
        mCanvasHeight = h;

        mCanvasHalfWidth = w / 2;
        mCanvasHalfHeight = h / 2;

        // are we in portrait or landscape mode now?
        // you could use bPortrait = !bPortrait however in the future who know's
        // how many different ways a device screen may be rotated.
        if (mCanvasHeight > mCanvasWidth)
            mPortrait = true;
        else {
            mPortrait = false;
            switchGameState(GAME_LANDSCAPE);
        }
    }

    /**
     * Called every cycle, used to process current game state.
     */
    public void gameTick() {
        // very basic state machine, makes a good foundation for a more complex
        // game.
        switch (mCurState) {
        case GAME_INIT:
            // prepare a new game for the user.
            initNewGame();
            switchGameState(GAME_RUNNING);

        case GAME_RUNNING:
            // update our marble.
            if (!mWarning)
                updateMarble();
            break;
        }

        // redraw the screen once our tick function is complete.
        invalidate();
    }

    /**
     * Reset game variables in preparation for a new game.
     */
    public void initNewGame() {
        mMarble.setLives(5);
        mTotalTime = 0;
        mlevel = 0;
        initLevel();
    }

    /**
     * Initialize the next level.
     */
    public void initLevel() {
        if (mlevel < mMaze.MAX_LEVELS) {
            // setup the next level.
            mWarning = true;
            mlevel++;
            mMaze.load(mActivity, mlevel);
            mMarble.init();
        } else {
            // user has finished the game, update state machine.
            switchGameState(GAME_COMPLETE);
        }
    }

    /**
     * Called from gameTick(), update marble x,y based on latest values obtained
     * from the Accelerometer sensor. AccelX and accelY are values received from
     * the accelerometer, higher values represent the device tilted at a more
     * acute angle.
     */
    public void updateMarble() {
        // we CAN give ourselves a buffer to stop the marble from rolling even
        // though we think the device is "flat".
        if (mAccelX > mSensorBuffer || mAccelX < -mSensorBuffer)
            mMarble.updateX(mAccelX);
        if (mAccelY > mSensorBuffer || mAccelY < -mSensorBuffer)
            mMarble.updateY(mAccelY);

        // check which cell the marble is currently occupying.
        if (mMaze.getCellType(mMarble.getX(), mMarble.getY()) == mMaze.VOID_TILE) {
            // user entered the "void".
            if (mMarble.getLives() > 0) {
                // user still has some lives remaining, restart the level.
                mMarble.death();
                mMarble.init();
                mWarning = true;
            } else {
                // user has no more lives left, end of game.
                mEndTime = System.currentTimeMillis();
                mTotalTime += mEndTime - mStartTime;
                switchGameState(GAME_OVER);
            }

        } else if (mMaze.getCellType(mMarble.getX(), mMarble.getY()) == mMaze.EXIT_TILE) {
            // user has reached the exit tiles, prepare the next level.
            mEndTime = System.currentTimeMillis();
            mTotalTime += mEndTime - mStartTime;
            initLevel();
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        // we only want to handle down events .
        if (event.getAction() == MotionEvent.ACTION_DOWN) {
            if (mCurState == GAME_OVER || mCurState == GAME_COMPLETE) {
                // re-start the game.
                mCurState = GAME_INIT;
            } else if (mCurState == GAME_RUNNING) {
                // in-game, remove the pop-up text so user can play.
                mWarning = false;
                mStartTime = System.currentTimeMillis();
            }
        }
        return true;
    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        // quit application if user presses the back key.
        if (keyCode == KeyEvent.KEYCODE_BACK)
            cleanUp();

        return true;
    }

    @Override
    public void onDraw(Canvas canvas) {
        // update our canvas reference.
        mCanvas = canvas;

        // clear the screen.
        mPaint.setColor(Color.WHITE);
        mCanvas.drawRect(0, 0, mCanvasWidth, mCanvasHeight, mPaint);

        // simple state machine, draw screen depending on the current state.
        switch (mCurState) {
        case GAME_RUNNING:
            // draw our maze first since everything else appears "on top" of it.
            mMaze.draw(mCanvas, mPaint);

            // draw our marble and hud.
            mMarble.draw(mCanvas, mPaint);

            // draw hud
            drawHUD();
            break;

        case GAME_OVER:
            drawGameOver();
            break;

        case GAME_COMPLETE:
            drawGameComplete();
            break;

        case GAME_LANDSCAPE:
            drawLandscapeMode();
            break;
        }

        gameTick();
    }

    /**
     * Called from onDraw(), draws the in-game HUD
     */
    public void drawHUD() {
        mPaint.setColor(Color.BLACK);
        mPaint.setTextAlign(Paint.Align.LEFT);
        mCanvas.drawText(mStrings[TXT_TIME] + ": " + (mTotalTime / 1000), mTextPadding, mHudTextY,
                mPaint);
        mPaint.setTextAlign(Paint.Align.CENTER);
        mCanvas.drawText(mStrings[TXT_LEVEL] + ": " + mlevel, mCanvasHalfWidth, mHudTextY, mPaint);
        mPaint.setTextAlign(Paint.Align.RIGHT);
        mCanvas.drawText(mStrings[TXT_LIVES] + ": " + mMarble.getLives(), mCanvasWidth - mTextPadding,
                mHudTextY, mPaint);

        // do we need to display the warning message to save the user from
        // possibly dying instantly.
        if (mWarning) {
            mPaint.setColor(Color.BLUE);
            mCanvas
                    .drawRect(0, mCanvasHalfHeight - 15, mCanvasWidth, mCanvasHalfHeight + 5,
                            mPaint);
            mPaint.setColor(Color.WHITE);
            mPaint.setTextAlign(Paint.Align.CENTER);
            mCanvas.drawText(mStrings[TXT_TAP_SCREEN], mCanvasHalfWidth, mCanvasHalfHeight, mPaint);
        }
    }

    /**
     * Called from onDraw(), draws the game over screen.
     */
    public void drawGameOver() {
        mPaint.setColor(Color.BLACK);
        mPaint.setTextAlign(Paint.Align.CENTER);

        mCanvas.drawText(mStrings[TXT_GAME_OVER], mCanvasHalfWidth, mCanvasHalfHeight, mPaint);
        mCanvas.drawText(mStrings[TXT_TOTAL_TIME] + ": " + (mTotalTime / 1000) + "s",
                mCanvasHalfWidth, mCanvasHalfHeight + mPaint.getFontSpacing(), mPaint);
        mCanvas.drawText(mStrings[TXT_GAME_OVER_MSG_A] + " " + (mlevel - 1) + " "
                + mStrings[TXT_GAME_OVER_MSG_B], mCanvasHalfWidth, mCanvasHalfHeight
                + (mPaint.getFontSpacing() * 2), mPaint);
        mCanvas.drawText(mStrings[TXT_RESTART], mCanvasHalfWidth, mCanvasHeight
                - (mPaint.getFontSpacing() * 3), mPaint);
    }

    /**
     * Called from onDraw(), draws the game complete screen.
     */
    public void drawGameComplete() {
        mPaint.setColor(Color.BLACK);
        mPaint.setTextAlign(Paint.Align.CENTER);
        mCanvas.drawText(mStrings[GAME_COMPLETE], mCanvasHalfWidth, mCanvasHalfHeight, mPaint);
        mCanvas.drawText(mStrings[TXT_TOTAL_TIME] + ": " + (mTotalTime / 1000) + "s",
                mCanvasHalfWidth, mCanvasHalfHeight + mPaint.getFontSpacing(), mPaint);
        mCanvas.drawText(mStrings[TXT_RESTART], mCanvasHalfWidth, mCanvasHeight
                - (mPaint.getFontSpacing() * 3), mPaint);
    }

    /**
     * Called from onDraw(), displays a message asking the user to return the
     * device back to portrait mode.
     */
    public void drawLandscapeMode() {
        mPaint.setColor(Color.WHITE);
        mPaint.setTextAlign(Paint.Align.CENTER);
        mCanvas.drawRect(0, 0, mCanvasWidth, mCanvasHeight, mPaint);
        mPaint.setColor(Color.BLACK);
        mCanvas.drawText(mStrings[TXT_LANDSCAPE_MODE], mCanvasHalfWidth, mCanvasHalfHeight, mPaint);
    }

    /**
     * Updates the current game state with a new state. At the moment this is
     * very basic however if the game was to get more complicated the code
     * required for changing game states could grow quickly.
     * 
     * @param newState
     *            New game state
     */
    public void switchGameState(int newState) {
        mCurState = newState;
    }

    /**
     * Register the accelerometer sensor so we can use it in-game.
     */
    public void registerListener() {
        mSensorManager.registerListener(mSensorAccelerometer, SensorManager.SENSOR_ACCELEROMETER,
                SensorManager.SENSOR_DELAY_GAME);
    }

    /**
     * Unregister the accelerometer sensor otherwise it will continue to operate
     * and report values.
     */
    public void unregisterListener() {
        mSensorManager.unregisterListener(mSensorAccelerometer);
    }

    /**
     * Clean up the custom view and exit the application.
     */
    public void cleanUp() {
        mMarble = null;
        mMaze = null;
        mStrings = null;
        unregisterListener();
        mActivity.finish();
    }
}


 

 

4. Amazed活动类,响应Activity来控制应用程序,定义和调用Amazed视图类,同时重载Activity的onResume方法和onSaveInstanceState方法分别进行Amazed类的注册和反注册

/*
 * Copyright (C) 2008 Jason Tomlinson.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.example.amazed;

import android.app.Activity;
import android.os.Bundle;
import android.view.Window;

/**
 * Activity responsible for controlling the application.响应Activity来控制应用程序
 */
public class AmazedActivity extends Activity {

    // custom view
    private AmazedView mView;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // remove title bar.
        requestWindowFeature(Window.FEATURE_NO_TITLE);

        // setup our view, give it focus and display.
        mView = new AmazedView(getApplicationContext(), this);
        mView.setFocusable(true);
        setContentView(mView);
    }

    @Override
    protected void onResume() {
        super.onResume();
        mView.registerListener();
    }

    @Override
    public void onSaveInstanceState(Bundle icicle) {
        super.onSaveInstanceState(icicle);
        mView.unregisterListener();
    }
}


 


源码来源:https://code.google.com/p/apps-for-android/
源码下载:http://download.csdn.net/user/yangzhenping

•Amazed: A simple but addictive accelerometer-based marble-guidance game.
•AndroidGlobalTime: a full representation of the Earth that you can spin around.
•AnyCut: A utility that lets users create Home screen shortcuts to nearly anything in the system.
•Clickin2DaBeat: A game that mashes up YouTube with custom rhythm-game logic.
•DivideAndConquer: a game in which you must isolate bouncing balls by creating walls around them.
•HeightMapProfiler: A simple 3D performance testing tool that renders a 3D height map.
•LOLcat Builder:
ho hai,i see in has cheese burger? I am in our phone, caption in our photos.
•Panoramio: An app that shows you nearby photos and points of interest.
•Photostream: An app that lets you view photostreams from online photo-hosting services.
•Radar: A radar-style relative location display view, used by Panoramio(Google照片分享服务) and others.
•RingsExtended: A utility that provides enhanced control over ringtones.
•Samples: Miscellaneous examples showing features of the Android platform (among which OpenGL ES).
•SpriteMethodTest: An application that compares the speed of various 2D sprite drawing methods.
•WebViewDemo: How Java and JavaScript can call each other inside a WebView.
•WikiNotes: A wiki note pad that uses intents to navigate to wiki words and other rich content stored in the notes.


•Amazed:一个简单但令人上瘾的加速度为基础的大理石指导游戏。
•AndroidGlobalTime:地球全表示,你可以不停地旋转。
•AnyCut:一种实用工具,可以让用户创建主屏幕快捷方式到系统中几乎任何东西。
•Clickin2DaBeat:一个游戏,捣烂了YouTube的自定义节奏的游戏逻辑。
•DivideAndConquer:一个游戏中,你必须隔离他们围绕创建墙壁弹跳球。
•HeightMapProfiler:一个简单的3D性能测试工具,它呈现一个三维高程图。
•LOLcat生成器:
何海,我看到有芝士汉堡?我在我们的电话,说明在我们的照片。
•Panoramio的:一个应用程序,显示你附近的照片和兴趣点。
•照片流:一个应用程序,让您从在线照片托管服务查看照片媒体。
•雷达:雷达式的相对位置显示视图,用于Panoramio的(谷歌照片分享服务)等。
•RingsExtended:提供增强的控制铃声的实用程序。
•Samples:显示Android平台(其中的OpenGL ES)的功能,其他的例子。
•SpriteMethodTest:用于比较各种2D精灵绘制方法速度的应用程序。
•WebViewDemo:如何Java与JavaScript可以调用对方的WebView里面。
•WikiNotes:使用意图导航到维基单词和存储在票据等丰富内容维基便条。

源码来源:https://code.google.com/p/apps-for-android/
源码下载:http://download.csdn.net/user/yangzhenping

目录
相关文章
|
6月前
|
存储 Java API
Android 浅度解析:mk预置AAR、SO文件、APP包和签名
Android 浅度解析:mk预置AAR、SO文件、APP包和签名
805 0
|
4月前
|
XML 自然语言处理 Android开发
🌐Android国际化与本地化全攻略!让你的App走遍全球无障碍!🌍
【7月更文挑战第28天】在全球化背景下,实现Android应用的国际化与本地化至关重要 for 用户基础扩展。本文通过旅游指南App案例,介绍全攻略。步骤包括资源文件拆分与命名、适配布局与方向、处理日期时间及货币格式、考虑文化习俗及进行详尽测试。采用Android Studio支持,创建如`res/values-en/strings.xml`等多语言资源文件夹,使用灵活布局解决文本长度差异问题,并通过用户反馈迭代优化。最终,打造一款能无缝融入全球各地文化的App。
190 3
|
4月前
|
消息中间件 Android开发 开发者
🔍深度剖析Android内存泄漏,让你的App远离崩溃边缘,稳如老狗!🐶
【7月更文挑战第28天】在 Android 开发中,内存管理至关重要。内存泄漏可悄无声息地累积,最终导致应用崩溃或性能下滑。它通常由不正确地持有 Activity 或 Fragment 的引用引起。常见原因包括静态变量持有组件引用、非静态内部类误用、Handler 使用不当、资源未关闭及集合对象未清理。使用 Android Studio Profiler 和 LeakCanary 可检测泄漏,修复方法涉及使用弱引用、改用静态内部类、妥善管理 Handler 和及时释放资源。良好的内存管理是保证应用稳定性的基石。
78 4
|
4月前
|
XML 缓存 Android开发
🎯解锁Android性能优化秘籍!让你的App流畅如飞,用户爱不释手!🚀
【7月更文挑战第28天】在移动应用竞争中,性能是关键。掌握Android性能优化技巧对开发者至关重要。
41 2
|
5月前
|
ARouter IDE 开发工具
Android面试题之App的启动流程和启动速度优化
App启动流程概括: 当用户点击App图标,Launcher通过Binder IPC请求system_server启动Activity。system_server指示Zygote fork新进程,接着App进程向system_server申请启动Activity。经过Binder通信,Activity创建并回调生命周期方法。启动状态分为冷启动、温启动和热启动,其中冷启动耗时最长。优化技巧包括异步初始化、避免主线程I/O、类加载优化和简化布局。
81 3
Android面试题之App的启动流程和启动速度优化
|
4月前
|
Android开发
Android面试题经典之如何全局替换App的字体
在Android应用中替换字体有全局和局部方法。全局替换涉及在`Application`的`onCreate`中设置自定义字体,并创建新主题。局部替换则可在布局中通过`ResourcesCompat.getFont()`加载字体文件并应用于`TextView`。
80 2
|
5月前
|
缓存 JSON 网络协议
Android面试题:App性能优化之电量优化和网络优化
这篇文章讨论了Android应用的电量和网络优化。电量优化涉及Doze和Standby模式,其中应用可能需要通过用户白名单或电池广播来适应限制。Battery Historian和Android Studio的Energy Profile是电量分析工具。建议减少不必要的操作,延迟非关键任务,合并网络请求。网络优化包括HTTPDNS减少DNS解析延迟,Keep-Alive复用连接,HTTP/2实现多路复用,以及使用protobuf和gzip压缩数据。其他策略如使用WebP图像格式,按网络质量提供不同分辨率的图片,以及启用HTTP缓存也是有效手段。
88 9
|
5月前
|
XML 监控 安全
Android App性能优化之卡顿监控和卡顿优化
本文探讨了Android应用的卡顿优化,重点在于布局优化。建议包括将耗时操作移到后台、使用ViewPager2实现懒加载、减少布局嵌套并利用merge标签、使用ViewStub减少资源消耗,以及通过Layout Inspector和GPU过度绘制检测来优化。推荐使用AsyncLayoutInflater异步加载布局,但需注意线程安全和不支持特性。卡顿监控方面,提到了通过Looper、ChoreographerHelper、adb命令及第三方工具如systrace和BlockCanary。总结了Choreographer基于掉帧计算和BlockCanary基于Looper监控的原理。
88 3
|
5月前
|
安全 Android开发 数据安全/隐私保护
同样的 APP 为何在 Android 8 以后网络感觉变卡?
【6月更文挑战第8天】Android 8 及以后系统中,APP 网络感觉变卡源于更严格的安全机制和后台限制,系统对网络优化的侧重改变,以及APP自身兼容性问题。开发者需优化APP,适应新系统,用户可更新APP或检查权限设置。通过共同努力,有望改善网络卡顿现象,提升用户体验。
92 3
|
5月前
|
Java Android开发 Kotlin
Android面试题:App性能优化之Java和Kotlin常见的数据结构
Java数据结构摘要:ArrayList基于数组,适合查找和修改;LinkedList适合插入删除;HashMap1.8后用数组+链表/红黑树,初始化时预估容量可避免扩容。SparseArray优化查找,ArrayMap减少冲突。 Kotlin优化摘要:Kotlin的List用`listOf/mutableListOf`,Map用`mapOf/mutableMapOf`,支持操作符重载和扩展函数。序列提供懒加载,解构用于遍历Map,扩展函数默认参数增强灵活性。
48 0

热门文章

最新文章