我照着Hello.Android.3rd.Edition.pdf写了一个九宫格游戏,能正常运行,运行后如图所示:然后点击New Game:
弹出Dialog:点击任意难度进入,出现错误:android has stopped unexpectedlyLogcat:12-14 01:16:29.082: D/Sudoku(288): clicked on……012-14 01:16:29.132: D/Sudoku(288): onCreate12-14 01:16:29.263: D/Sudoku(288): onSizeChanged:width 35.555557,height 47.7777812-14 01:16:29.372: D/AndroidRuntime(288): Shutting down VM12-14 01:16:29.372: W/dalvikvm(288): threadid=1: thread exiting with uncaught exception (group=0x4001d800)12-14 01:16:29.412: E/AndroidRuntime(288): FATAL EXCEPTION: main12-14 01:16:29.412: E/AndroidRuntime(288): java.lang.NullPointerException12-14 01:16:29.412: E/AndroidRuntime(288):  at org.example.Sudoku.PuzzleView.onDraw(PuzzleView.java:162)12-14 01:16:29.412: E/AndroidRuntime(288):  at android.view.View.draw(View.java:6740)12-14 01:16:29.412: E/AndroidRuntime(288):  at android.view.ViewGroup.drawChild(ViewGroup.java:1640)12-14 01:16:29.412: E/AndroidRuntime(288):  at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1367)12-14 01:16:29.412: E/AndroidRuntime(288):  at android.view.View.draw(View.java:6743)12-14 01:16:29.412: E/AndroidRuntime(288):  at android.widget.FrameLayout.draw(FrameLayout.java:352)12-14 01:16:29.412: E/AndroidRuntime(288):  at android.view.ViewGroup.drawChild(ViewGroup.java:1640)12-14 01:16:29.412: E/AndroidRuntime(288):  at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1367)12-14 01:16:29.412: E/AndroidRuntime(288):  at android.view.ViewGroup.drawChild(ViewGroup.java:1638)12-14 01:16:29.412: E/AndroidRuntime(288):  at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1367)12-14 01:16:29.412: E/AndroidRuntime(288):  at android.view.View.draw(View.java:6743)12-14 01:16:29.412: E/AndroidRuntime(288):  at android.widget.FrameLayout.draw(FrameLayout.java:352)12-14 01:16:29.412: E/AndroidRuntime(288):  at com.android.internal.policy.impl.PhoneWindow$DecorView.draw(PhoneWindow.java:1842)12-14 01:16:29.412: E/AndroidRuntime(288):  at android.view.ViewRoot.draw(ViewRoot.java:1407)12-14 01:16:29.412: E/AndroidRuntime(288):  at android.view.ViewRoot.performTraversals(ViewRoot.java:1163)12-14 01:16:29.412: E/AndroidRuntime(288):  at android.view.ViewRoot.handleMessage(ViewRoot.java:1727)12-14 01:16:29.412: E/AndroidRuntime(288):  at android.os.Handler.dispatchMessage(Handler.java:99)12-14 01:16:29.412: E/AndroidRuntime(288):  at android.os.Looper.loop(Looper.java:123)12-14 01:16:29.412: E/AndroidRuntime(288):  at android.app.ActivityThread.main(ActivityThread.java:4627)12-14 01:16:29.412: E/AndroidRuntime(288):  at java.lang.reflect.Method.invokeNative(Native Method)12-14 01:16:29.412: E/AndroidRuntime(288):  at java.lang.reflect.Method.invoke(Method.java:521)12-14 01:16:29.412: E/AndroidRuntime(288):  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)12-14 01:16:29.412: E/AndroidRuntime(288):  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)12-14 01:16:29.412: E/AndroidRuntime(288):  at dalvik.system.NativeStart.main(Native Method)我前面只知道这种错误是由于没注册Activity造成的,但我全部注册了
请问从这个日志能看出错误在哪吗?有很多个CLASS,我也不知道该帖哪段代码出来  private static final String TAG = "Sudoku";
    
    private void openNewGameDialog() {
     new AlertDialog.Builder(this).setTitle(R.string.new_game_title).setItems(R.array.difficulty,new DialogInterface.OnClickListener() {

public void onClick(DialogInterface dialoginterface, int i) {
startGame(i);
// TODO Auto-generated method stub
}
}).show();
}
    
    private void startGame(int i) {
Log.d(TAG, "clicked on……"+i);
Intent intent = new Intent(Sudoku.this,Game.class);
intent.putExtra(Game.KEY_DIFFICULTY, i);
startActivity(intent);
//Start game click here
}
}先谢谢各位了,请帮我看看,第一次做就受挫了……

解决方案 »

  1.   

    谢谢您的回答,我的
    PuzzleView.java的内容如下:162行已标识package org.example.Sudoku;import android.content.Context;
    import android.graphics.Canvas;
    import android.graphics.Paint;
    import android.graphics.Paint.FontMetrics;
    import android.graphics.Paint.Style;
    import android.graphics.Rect;
    import android.util.Log;
    import android.view.KeyEvent;
    import android.view.MotionEvent;
    import android.view.View;
    import android.view.animation.AnimationUtils;public class PuzzleView extends View {
    private static final String TAG = "Sudoku";
    private final Game game; public PuzzleView(Context context) {
    super(context);
    this.game = (Game) context;
    setFocusable(true);
    setFocusableInTouchMode(true);
    // TODO Auto-generated constructor stub
    } @Override
    public boolean onTouchEvent(MotionEvent event) {
    // TODO Auto-generated method stub
    if (event.getAction() != MotionEvent.ACTION_DOWN)
    return super.onTouchEvent(event);
    select((int) (event.getX() / width), (int) (event.getY() / height));
    game.showKeypadOrError(selX, selY);
    Log.d(TAG, "onTouchEvent:x " + selX + ",y " + selY);
    return true; } // setSelectTile()方法
    public void setSelectTile(int tile) {
    if (game.setTileIfValid(selX, selY, tile)) {
    invalidate(); // may change hints
    } else {
    // number is not valid for this hints
    Log.d(TAG, "selectedTile : invalid : " + tile);
    startAnimation(AnimationUtils.loadAnimation(game, R.anim.shake));
    } } @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
    // TODO Auto-generated method stub
    Log.d(TAG, "onKeyDown:keycode = " + keyCode + ",event=" + event); switch (keyCode) {
    case KeyEvent.KEYCODE_DPAD_UP:
    select(selX, selY - 1);
    break;
    case KeyEvent.KEYCODE_DPAD_DOWN:
    select(selX, selY + 1);
    break;
    case KeyEvent.KEYCODE_DPAD_LEFT:
    select(selX - 1, selY);
    break;
    case KeyEvent.KEYCODE_DPAD_RIGHT:
    select(selX + 1, selY);
    break;
    case KeyEvent.KEYCODE_0:
    case KeyEvent.KEYCODE_SPACE:
    setSelectTile(0);
    break;
    case KeyEvent.KEYCODE_1:
    setSelectTile(1);
    break;
    case KeyEvent.KEYCODE_2:
    setSelectTile(2);
    break;
    case KeyEvent.KEYCODE_3:
    setSelectTile(3);
    break;
    case KeyEvent.KEYCODE_4:
    setSelectTile(4);
    break;
    case KeyEvent.KEYCODE_5:
    setSelectTile(5);
    break;
    case KeyEvent.KEYCODE_6:
    setSelectTile(6);
    break;
    case KeyEvent.KEYCODE_7:
    setSelectTile(7);
    break;
    case KeyEvent.KEYCODE_8:
    setSelectTile(8);
    break;
    case KeyEvent.KEYCODE_9:
    setSelectTile(9);
    break;
    case KeyEvent.KEYCODE_ENTER:
    case KeyEvent.KEYCODE_DPAD_CENTER:
    game.showKeypadOrError(selX, selY);
    break; default:
    return super.onKeyDown(keyCode, event);
    }
    return true;
    } // select() 方法
    private void select(int x, int y) {
    invalidate(selRect);
    selX = Math.min(Math.max(x, 0), 8);
    selY = Math.min(Math.max(y, 0), 8);
    getRect(selX, selY, selRect);
    invalidate(selRect);
    } @Override
    protected void onDraw(Canvas canvas) {
    // TODO Auto-generated method stub
    // super.onDraw(canvas);
    // Draw the background……
    Paint background = new Paint();
    background.setColor(getResources().getColor(R.color.puzzle_background));
    canvas.drawRect(0, 0, getWidth(), getHeight(), background); // Draw the board……
    // Define colors for the grid lines
    Paint dark = new Paint();
    dark.setColor(getResources().getColor(R.color.puzzle_dark)); Paint hilite = new Paint();
    hilite.setColor(getResources().getColor(R.color.puzzle_hilite)); Paint light = new Paint();
    light.setColor(getResources().getColor(R.color.puzzle_light)); // Draw the minor grid lines
    for (int i = 0; i < 9; i++) {
    canvas.drawLine(0, i * height, getWidth(), i * height, light);
    canvas.drawLine(0, i * height + 1, getWidth(), i * height + 1,
    hilite);
    canvas.drawLine(i * width, 0, i * width, getHeight(), light);
    canvas.drawLine(i * width + 1, 0, i * width + 1, getHeight(),
    hilite); }
    // Draw the major grid lines
    for (int i = 0; i < 9; i++) {
    if (i % 3 != 0)
    continue;
    canvas.drawLine(0, i * height, getWidth(), i * height, dark);
    canvas.drawLine(0, i * height + 1, getWidth(), i * height + 1,
    hilite);
    canvas.drawLine(i * width, 0, i * width, getHeight(), dark);
    canvas.drawLine(i * width + 1, 0, i * width + 1, getHeight(),
    hilite);
    }
    // Draw the numbers……
    // Define color and style for numbers
    Paint foreground = new Paint(Paint.ANTI_ALIAS_FLAG);
    foreground.setColor(getResources().getColor(R.color.puzzle_foreground));
    foreground.setStyle(Style.FILL);
    foreground.setTextSize(height * 0.75f);
    foreground.setTextScaleX(width / height);
    foreground.setTextAlign(Paint.Align.CENTER); // Draw the number in the center of the tile
    FontMetrics fm = foreground.getFontMetrics();
    // Centering in x:use alignment (and X at midpoint)
    float x = width / 2;
    // Centering in Y : measure ascent/descent first
    float y = height / 2 - (fm.ascent + fm.descent) / 2;
    for (int i = 0; i < 9; i++) {
    for (int j = 0; j < 9; j++) {
    canvas.drawText(this.game.getTileString(i, j), i * width + x, j
    * height + y, foreground);
    }
    } // Draw the hints……
    // Pick a hint color based on #moves left
    Paint hint = new Paint();
    int c[] = { getResources().getColor(R.color.puzzle_hint_0),
    getResources().getColor(R.color.puzzle_hint_1),
    getResources().getColor(R.color.puzzle_hint_2), };
    Rect r = new Rect();
    for (int i = 0; i < 9; i++) {
    for (int j = 0; j < 9; j++) {
    int movesleft = 9 - game.getUsedTiles(i, j).length; //这一行即报错中的162行  --- if (movesleft < c.length) {
    getRect(i, j, r);
    hint.setColor(c[movesleft]);
    canvas.drawRect(r, hint);
    }
    }
    }
    // Draw the selection……
    Log.d(TAG, "selRect=" + selRect);
    Paint selected = new Paint();
    selected.setColor(getResources().getColor(R.color.puzzle_selected));
    canvas.drawRect(selRect, selected); } private float width;
    private float height;
    private int selX;
    private int selY;
    private final Rect selRect = new Rect(); @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    // TODO Auto-generated method stub
    width = w / 9f;
    height = h / 9f;
    getRect(selX, selY, selRect);
    Log.d(TAG, "onSizeChanged:width " + width + ",height " + height);
    super.onSizeChanged(w, h, oldw, oldh);
    } private void getRect(int x, int y, Rect rect) {
    rect.set((int) (x * width), (int) (y * height),
    (int) (x * width + width), (int) (y * height + height)); }}
    请大家帮我看看,我没找出问题
      

  2.   

    代码中不能加颜色,重新把上一楼发一下:package org.example.Sudoku;import android.content.Context;
    import android.graphics.Canvas;
    import android.graphics.Paint;
    import android.graphics.Paint.FontMetrics;
    import android.graphics.Paint.Style;
    import android.graphics.Rect;
    import android.util.Log;
    import android.view.KeyEvent;
    import android.view.MotionEvent;
    import android.view.View;
    import android.view.animation.AnimationUtils;public class PuzzleView extends View {
    private static final String TAG = "Sudoku";
    private final Game game; public PuzzleView(Context context) {
    super(context);
    this.game = (Game) context;
    setFocusable(true);
    setFocusableInTouchMode(true);
    // TODO Auto-generated constructor stub
    } @Override
    public boolean onTouchEvent(MotionEvent event) {
    // TODO Auto-generated method stub
    if (event.getAction() != MotionEvent.ACTION_DOWN)
    return super.onTouchEvent(event);
    select((int) (event.getX() / width), (int) (event.getY() / height));
    game.showKeypadOrError(selX, selY);
    Log.d(TAG, "onTouchEvent:x " + selX + ",y " + selY);
    return true; } // setSelectTile()方法
    public void setSelectTile(int tile) {
    if (game.setTileIfValid(selX, selY, tile)) {
    invalidate(); // may change hints
    } else {
    // number is not valid for this hints
    Log.d(TAG, "selectedTile : invalid : " + tile);
    startAnimation(AnimationUtils.loadAnimation(game, R.anim.shake));
    } } @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
    // TODO Auto-generated method stub
    Log.d(TAG, "onKeyDown:keycode = " + keyCode + ",event=" + event); switch (keyCode) {
    case KeyEvent.KEYCODE_DPAD_UP:
    select(selX, selY - 1);
    break;
    case KeyEvent.KEYCODE_DPAD_DOWN:
    select(selX, selY + 1);
    break;
    case KeyEvent.KEYCODE_DPAD_LEFT:
    select(selX - 1, selY);
    break;
    case KeyEvent.KEYCODE_DPAD_RIGHT:
    select(selX + 1, selY);
    break;
    case KeyEvent.KEYCODE_0:
    case KeyEvent.KEYCODE_SPACE:
    setSelectTile(0);
    break;
    case KeyEvent.KEYCODE_1:
    setSelectTile(1);
    break;
    case KeyEvent.KEYCODE_2:
    setSelectTile(2);
    break;
    case KeyEvent.KEYCODE_3:
    setSelectTile(3);
    break;
    case KeyEvent.KEYCODE_4:
    setSelectTile(4);
    break;
    case KeyEvent.KEYCODE_5:
    setSelectTile(5);
    break;
    case KeyEvent.KEYCODE_6:
    setSelectTile(6);
    break;
    case KeyEvent.KEYCODE_7:
    setSelectTile(7);
    break;
    case KeyEvent.KEYCODE_8:
    setSelectTile(8);
    break;
    case KeyEvent.KEYCODE_9:
    setSelectTile(9);
    break;
    case KeyEvent.KEYCODE_ENTER:
    case KeyEvent.KEYCODE_DPAD_CENTER:
    game.showKeypadOrError(selX, selY);
    break; default:
    return super.onKeyDown(keyCode, event);
    }
    return true;
    } // select() 方法
    private void select(int x, int y) {
    invalidate(selRect);
    selX = Math.min(Math.max(x, 0), 8);
    selY = Math.min(Math.max(y, 0), 8);
    getRect(selX, selY, selRect);
    invalidate(selRect);
    } @Override
    protected void onDraw(Canvas canvas) {
    // TODO Auto-generated method stub
    // super.onDraw(canvas);
    // Draw the background……
    Paint background = new Paint();
    background.setColor(getResources().getColor(R.color.puzzle_background));
    canvas.drawRect(0, 0, getWidth(), getHeight(), background); // Draw the board……
    // Define colors for the grid lines
    Paint dark = new Paint();
    dark.setColor(getResources().getColor(R.color.puzzle_dark)); Paint hilite = new Paint();
    hilite.setColor(getResources().getColor(R.color.puzzle_hilite)); Paint light = new Paint();
    light.setColor(getResources().getColor(R.color.puzzle_light)); // Draw the minor grid lines
    for (int i = 0; i < 9; i++) {
    canvas.drawLine(0, i * height, getWidth(), i * height, light);
    canvas.drawLine(0, i * height + 1, getWidth(), i * height + 1,
    hilite);
    canvas.drawLine(i * width, 0, i * width, getHeight(), light);
    canvas.drawLine(i * width + 1, 0, i * width + 1, getHeight(),
    hilite); }
    // Draw the major grid lines
    for (int i = 0; i < 9; i++) {
    if (i % 3 != 0)
    continue;
    canvas.drawLine(0, i * height, getWidth(), i * height, dark);
    canvas.drawLine(0, i * height + 1, getWidth(), i * height + 1,
    hilite);
    canvas.drawLine(i * width, 0, i * width, getHeight(), dark);
    canvas.drawLine(i * width + 1, 0, i * width + 1, getHeight(),
    hilite);
    }
    // Draw the numbers……
    // Define color and style for numbers
    Paint foreground = new Paint(Paint.ANTI_ALIAS_FLAG);
    foreground.setColor(getResources().getColor(R.color.puzzle_foreground));
    foreground.setStyle(Style.FILL);
    foreground.setTextSize(height * 0.75f);
    foreground.setTextScaleX(width / height);
    foreground.setTextAlign(Paint.Align.CENTER); // Draw the number in the center of the tile
    FontMetrics fm = foreground.getFontMetrics();
    // Centering in x:use alignment (and X at midpoint)
    float x = width / 2;
    // Centering in Y : measure ascent/descent first
    float y = height / 2 - (fm.ascent + fm.descent) / 2;
    for (int i = 0; i < 9; i++) {
    for (int j = 0; j < 9; j++) {
    canvas.drawText(this.game.getTileString(i, j), i * width + x, j
    * height + y, foreground);
    }
    } // Draw the hints……
    // Pick a hint color based on #moves left
    Paint hint = new Paint();
    int c[] = { getResources().getColor(R.color.puzzle_hint_0),
    getResources().getColor(R.color.puzzle_hint_1),
    getResources().getColor(R.color.puzzle_hint_2), };
    Rect r = new Rect();
    for (int i = 0; i < 9; i++) {
    for (int j = 0; j < 9; j++) {
    int movesleft = 9 - game.getUsedTiles(i, j).length; //这一行即报错中的162行  ---
    if (movesleft < c.length) {
    getRect(i, j, r);
    hint.setColor(c[movesleft]);
    canvas.drawRect(r, hint);
    }
    }
    }
    // Draw the selection……
    Log.d(TAG, "selRect=" + selRect);
    Paint selected = new Paint();
    selected.setColor(getResources().getColor(R.color.puzzle_selected));
    canvas.drawRect(selRect, selected); } private float width;
    private float height;
    private int selX;
    private int selY;
    private final Rect selRect = new Rect(); @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    // TODO Auto-generated method stub
    width = w / 9f;
    height = h / 9f;
    getRect(selX, selY, selRect);
    Log.d(TAG, "onSizeChanged:width " + width + ",height " + height);
    super.onSizeChanged(w, h, oldw, oldh);
    } private void getRect(int x, int y, Rect rect) {
    rect.set((int) (x * width), (int) (y * height),
    (int) (x * width + width), (int) (y * height + height)); }}
      

  3.   


     int movesleft = 9 - game.getUsedTiles(i, j).length;这行会出现空指针的唯一情况,就是game.getUsedTitles(i,j)返回的是Null,null调用.length当然就会出现空指针异常,因为你没有给出Game类的代码和getUsedTitles(i,j),所以也不好跟你做什么分析,还是你自己多调试调试吧
      

  4.   

    我是自己在前面加了句IFif(getUsedTiles(i, j) != null){
    int movesleft = 9 - game.getUsedTiles(i, j).length;
    ……
    }算是临时解决了问题,不知道有没有什么隐患
      

  5.   

    隐患肯定会有,假如getUsedTitles(i,j)真的存在返回null的情况,那么就相当于你跑出这个例外情况不管,从完美程序角度的来看,程序不具有完美的包容性