Android:从Runnable活动启动活动(NullPointerException)

时间:2016-04-07 01:28:20

标签: android android-studio android-activity

我有一个可以绘制动画的Runnable GameView,它在NewGame活动中创建并使用。 NewGame启动另一个名为PetInfo的活动,点击视图上的按钮。但是,每当我启动PetInfo时,我都会收到以下错误:

  

04-06 19:13:30.025 23272-23272 /?我/艺术:延迟启用-Xcheck:jni

     

04-06 19:13:30.211 23272-23312 / com.example.xuan.tictactoe D / OpenGLRenderer:使用EGL_SWAP_BEHAVIOR_PRESERVED:true

     

04-06 19:13:30.219 23272-23272 / com.example.xuan.tictactoe D / Atlas:验证地图......

     

04-06 19:13:30.245 23272-23312 / com.example.xuan.tictactoe I / Adreno-EGL :: QUALCOMM Build:01/14/15,ab0075f,Id3510ff6dc

     

04-06 19:13:30.246 23272-23312 / com.example.xuan.tictactoe I / OpenGLRenderer:初始化的EGL,版本1.4

     

04-06 19:13:30.267 23272-23312 / com.example.xuan.tictactoe D / OpenGLRenderer:启用调试模式0

     

04-06 19:14:40.950 23272-23272 / com.example.xuan.tictactoe D / test:onCreate

     

04-06 19:14:40.956 23272-23272 / com.example.xuan.tictactoe D / test:设置视图后的onCreate

     

04-06 19:14:41.161 23272-24500 / com.example.xuan.tictactoe E / AndroidRuntime:FATAL EXCEPTION:Thread-8231

     
    

处理:com.example.xuan.tictactoe,PID:23272

         

java.lang.NullPointerException:尝试在空对象引用上调用虚方法'void android.graphics.Canvas.drawColor(int)'

         
      

at com.example.xuan.tictactoe.GameView.draw(GameView.java:135)

             

at com.example.xuan.tictactoe.GameView.run(GameView.java:100)

             

在java.lang.Thread.run(Thread.java:818)

    
  

NewGame 活动

public class NewGame extends Activity {
GameView game_view;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    game_view = new GameView(this);

    setContentView(R.layout.activity_new_game);
  }


  // This method executes when the player starts the game
  @Override
  protected void onResume() {
    super.onResume();

    // Tell the gameView resume method to execute
    game_view.resume();
  }

  // This method executes when the player quits the game
  @Override
  protected void onPause() {
    super.onPause();

    // Tell the gameView pause method to execute
    game_view.pause();
  }

  // Start new activity
  public void createInfo(View view) {
    Intent intent = new Intent(this, PetInfo.class);
    startActivity(intent);
  }
}

GameView.java

public class GameView extends SurfaceView implements Runnable {
Thread game_thread = null;

// SurfaceHolder for Paint and Canvas in a thread
SurfaceHolder the_holder;

// Canvas and Paint objects
Canvas canvas;
Paint paint;
Bitmap dragon;

volatile boolean is_running;

long fps; // tracks the game frame rate
private long time_this_frame; // calculate the fps
float x_position = 0;  // start position
float y_position = 0;
long frame_ticker = 0l;

// New variables for spritesheet
private int frame_count = 10;  // How many frames are there on the sprite sheet?
private int sprite_width = 600;
private int sprite_height = 450;
private int current_frame = 0; // Start at the first frame - where else?

// A rectangle to define an area of the sprite sheet that represents 1 frame
private Rect frame_to_draw = new Rect(0, 0, sprite_width, sprite_height);

// A rect that defines an area of the screen on which to draw
RectF where_to_draw = new RectF(x_position, 0, x_position + sprite_width, sprite_height);

// Constructor methods
public GameView(Context context) {
    super(context);
    init(context);
}

public GameView(Context context, AttributeSet attrs) {
    super(context, attrs);
    init(context);
}

public GameView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    init(context);
}

private void init(Context context) {
    // Initialize ourHolder and paint objects
    the_holder = getHolder();
    the_holder.addCallback(new SurfaceHolder.Callback() {
        @Override
        public void surfaceDestroyed(SurfaceHolder holder) {
            pause();
        }

        @Override
        public void surfaceCreated(SurfaceHolder holder) {
            resume();
        }

        @Override
        public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

        }
    });

    paint = new Paint();

    // Load dragon from .png file
    dragon = BitmapFactory.decodeResource(this.getResources(), R.drawable.gd10_spritesheet);
}

@Override
public void run() {
    while (is_running) {
        // Capture the current time in milliseconds in startFrameTime
        long startFrameTime = System.currentTimeMillis();

        update();  // Update the frame
        draw(); // Draw the frame

        // Calculate the fps this frame to time animations.
        time_this_frame = System.currentTimeMillis() - startFrameTime;
        if (time_this_frame >= 1) {
            fps = 5000 / time_this_frame;
        }
    }
}

// Everything that needs to be updated goes in here
// In later projects we will have dozens (arrays) of objects.
// We will also do other things like collision detection.
public void update() {
    long game_time = System.currentTimeMillis();

    if (game_time > (frame_ticker + fps)) {
        frame_ticker = game_time;

        current_frame++;
        if (current_frame >= frame_count) {
            current_frame = 0;
        }
    }

    frame_to_draw.left = current_frame * sprite_width;
    frame_to_draw.right = frame_to_draw.left + sprite_width;
}

// Draw the newly updated scene
public void draw() {
    // Make sure our drawing surface is valid or we crash
    if (the_holder.getSurface().isValid()) {

        canvas = the_holder.lockCanvas(); // Lock the canvas ready to draw
        canvas.drawColor(Color.argb(255, 144, 195, 212)); // Draw the background color
        paint.setColor(Color.argb(255, 249, 129, 0)); // Choose the brush color for drawing

        x_position = (float) (this.getWidth()/2.0 - frame_to_draw.width()/2.0);
        y_position = (float) (this.getHeight()/4.0 - frame_to_draw.height()/2.0);

        where_to_draw.set((int) x_position,
                (int) y_position,
                (int) x_position + sprite_width,
                (int) y_position + sprite_height);

        canvas.drawBitmap(dragon,
                frame_to_draw,
                where_to_draw, paint);

        the_holder.unlockCanvasAndPost(canvas); // Draw everything to the screen
    }
}

// If activity is paused/stopped shutdown our thread.
public void pause() {
    is_running = false;
    try {
        game_thread.join();
    } catch (InterruptedException e) {
        Log.e("Error:", "joining thread");
    }
    game_thread = null;

}

// If activity is started then start our thread.
public void resume() {
    is_running = true;
    game_thread = new Thread(this);
    game_thread.start();
}
}

activity_new_game.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.xuan.tictactoe.NewGame">

<com.example.xuan.tictactoe.GameView
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

<Button
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_centerHorizontal="true"
    android:layout_alignParentBottom="true"
    android:text="OK"
    android:onClick="createInfo"/>

</RelativeLayout>

有趣的是,我在PetInfo创建了一些登录onCreate并且日志运行,这意味着创建了PetInfo活动,但由于某些原因,它会在上一个活动的线程上抛出错误(是NewGame的{​​{1}})。

有什么想法吗?谢谢!

1 个答案:

答案 0 :(得分:-1)

Runnable =不同/后台线程,不是主线程。这使得在Runnable内部完成的代码能够在不锁定主/ UI线程的情况下花费很长时间。

但是,这也意味着您无法从其他/后台线程更新主/ UI线程。您只能在Runnable操作完成后更新UI线程,并且您已离开Runnable块。