![](/img/trans.png)
[英]My app keeps crashing when I intent from a Fragment to a new Activity (Android)
[英]My app keeps crashing when I Open the Game Activity. I tried to create a game activity to be opened from the main activity
當我從 Home Activity 中打開帶有 Intent 的 Game Activity 時,應用程序會在游戲 Activity 啟動時立即崩潰。 游戲活動基本上是一個用畫布繪制蛇的蛇游戲。 請幫助是否有特定原因或我的代碼有問題? 我將在下面刪除我的游戲活動代碼和清單
這是游戲活動代碼
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.AppCompatImageButton;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.os.Bundle;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;
public class GameActivity extends AppCompatActivity implements SurfaceHolder.Callback {
// list snake points / snake length
private List<SnakePoints> snakePointsList = new ArrayList<>();
private SurfaceView surfaceView;
private TextView scoreTV;
// surface holder draws the snake on the surface's canvas
private SurfaceHolder surfaceHolder;
// snake moving position. Values can be right, left, top, bottom.
// by default, snake mover to right.
private String movingPosition = "right";
// score
private int score = 0;
// snake size / point size
private static final int pointSize = 28;
// default tail size
private static final int defaultTailPoints = 3;
// snake color
private static final int snakeColor = Color.YELLOW;
// snake speed
private static final int snakeMovingSpeed = 800;
// random point coordinates on the surfaceView
private int positionX, positionY;
// timer to move snake / change snake position after a specific time
private Timer timer;
// canvas to draw snake and show on surfaceView
private Canvas canvas = null;
//point color / single point color of a snake
private Paint pointColor = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_game);
// getting surfaceView and score TextView from xml file
surfaceView = findViewById(R.id.surfaceView);
scoreTV = findViewById(R.id.scoreTV);
// getting image buttons from xml file
final AppCompatImageButton topBtn = findViewById(R.id.topBtn);
final AppCompatImageButton leftBtn = findViewById(R.id.leftBtn);
final AppCompatImageButton rightBtn = findViewById(R.id.rightBtn);
final AppCompatImageButton bottomBtn = findViewById(R.id.bottomBtn);
// call back to surfaceView
surfaceView.getHolder().addCallback(this);
topBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (!movingPosition.equals("bottom")){
movingPosition = "top";
}
}
});
leftBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (!movingPosition.equals("right")){
movingPosition = "left";
}
}
});
rightBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (!movingPosition.equals("left")){
movingPosition = "right";
}
}
});
bottomBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (!movingPosition.equals("top")){
movingPosition = "bottom";
}
}
});
}
@Override
public void surfaceCreated(@NonNull SurfaceHolder holder) {
// when the surface is created, get surfaceHolder and assign it to surfaceHolder
this.surfaceHolder = surfaceHolder;
// initialize data for snake / surfaceView
init();
}
@Override
public void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width, int height) {
}
@Override
public void surfaceDestroyed(@NonNull SurfaceHolder holder) {
}
private void init(){
// clear the snake points / length
snakePointsList.clear();
// set default score
scoreTV.setText("0");
// make score 0
score = 0;
// default moving position is right
movingPosition = "right";
// default snake starting position on the screen
int startPositionX = (pointSize) * defaultTailPoints;
// making snake's default length / points
for (int i = 0; i < defaultTailPoints; i++){
// adding points to snake tail
SnakePoints snakePoints = new SnakePoints(startPositionX, pointSize);
snakePointsList.add(snakePoints);
// increasing the value for the next snake tail
startPositionX = startPositionX - (pointSize * 2);
}
// add random point on the screen to be eaten by snake
addPoint();
// start moving the snake / start game
moveSnake();
}
private void addPoint(){
// getting surfaceView width and height to add point on the surface to be eaten by the snake
int surfaceWidth = surfaceView.getWidth() - (pointSize * 2);
int surfaceHeight = surfaceView.getHeight() - (pointSize * 2);
int randomXPosition = new Random().nextInt(surfaceWidth / pointSize);
int randomYPosition = new Random().nextInt(surfaceHeight / pointSize);
//check if randomXPosition is even orr odd value coz we need only even number
if ((randomXPosition % 2) != 0){
randomXPosition = randomXPosition + 1;
}
if ((randomYPosition % 2) != 0){
randomYPosition = randomYPosition + 1;
}
positionX = (pointSize * randomXPosition) + pointSize;
positionY = (pointSize * randomYPosition) + pointSize;
}
private void moveSnake(){
timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
// getting head position
int headPositionX = snakePointsList.get(0).getPositionX();
int headPositionY = snakePointsList.get(0).getPositionY();
// to check if the snake has eaten a point
if (headPositionX == positionX && positionY == headPositionY){
//grow snake after eating
growSnake();
// add another random point on the screen
addPoint();
}
// check which side the snake is moving
switch (movingPosition){
case "right":
//move snakes head to right
snakePointsList.get(0).setPositionX(headPositionX + (pointSize * 2));
snakePointsList.get(0).setPositionY(headPositionY);
break;
case "left":
//move snakes head to left
snakePointsList.get(0).setPositionX(headPositionX - (pointSize * 2));
snakePointsList.get(0).setPositionY(headPositionY);
break;
case "top":
//move snakes head to top
snakePointsList.get(0).setPositionX(headPositionX);
snakePointsList.get(0).setPositionY(headPositionY - (pointSize * 2));
break;
case "bottom":
//move snakes head to bottom
snakePointsList.get(0).setPositionX(headPositionX);
snakePointsList.get(0).setPositionY(headPositionY + (pointSize * 2));
break;
}
//check if game is over. Weather snake touch edges or snake itself
if (checkGameOver(headPositionX, headPositionY)){
//stop timer / stop moving snake
timer.purge();
timer.cancel();
//game over dialogue
AlertDialog.Builder builder = new AlertDialog.Builder(GameActivity.this);
builder.setMessage("Your Score = " +score);
builder.setTitle("Game Over");
builder.setCancelable(false);
builder.setPositiveButton("Go back", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
// return
Intent intent = new Intent(GameActivity.this, HomeActivity.class);
startActivity(intent);
}
});
//timer runs in background so show dialogue in main thread
runOnUiThread(new Runnable() {
@Override
public void run() {
builder.show();
}
});
}
else {
//lock canvas on surfaceHolder to draw on it
canvas = surfaceHolder.lockCanvas();
//clear canvas with white color
canvas.drawColor(Color.WHITE, PorterDuff.Mode.CLEAR);
// change snake's head position. Other snake points will follow snake's head
canvas.drawCircle(snakePointsList.get(0).getPositionX(), snakePointsList.get(0).getPositionY(), pointSize, createPointColor());
// draw random point circles on the surface to be eaten by the snake
canvas.drawCircle(positionX, positionY, pointSize, createPointColor());
// all other points following snake's head position 0 is head of snake
for (int i = 1; i < snakePointsList.size(); i++){
int getTempPositionX = snakePointsList.get(i).getPositionX();
int getTempPositionY = snakePointsList.get(i).getPositionY();
// move points across the head
snakePointsList.get(i).setPositionX(headPositionX);
snakePointsList.get(i).setPositionY(headPositionY);
canvas.drawCircle(snakePointsList.get(i).getPositionX(), snakePointsList.get(i).getPositionY(), pointSize, createPointColor());
//change head position
headPositionX = getTempPositionX;
headPositionY = getTempPositionY;
}
//unlock canvas to draw on surfaceView
surfaceHolder.unlockCanvasAndPost(canvas);
}
}
}, 1000- snakeMovingSpeed, 1000- snakeMovingSpeed);
}
private void growSnake(){
// create new snake points
SnakePoints snakePoints = new SnakePoints(0,0);
//add points to the snake's tail
snakePointsList.add(snakePoints);
//increase score
score++;
//setting score to textView
runOnUiThread(new Runnable() {
@Override
public void run() {
scoreTV.setText(String.valueOf(score));
}
});
}
private boolean checkGameOver(int headPositionX, int headPositionY){
boolean gameOver = false;
//check if snake's head touches edges
if (snakePointsList.get(0).getPositionX() < 0 ||
snakePointsList.get(0).getPositionY() < 0 ||
snakePointsList.get(0).getPositionX() >= surfaceView.getWidth() ||
snakePointsList.get(0).getPositionY() >= surfaceView.getHeight()){
gameOver = true;
}
else {
//check if snake's head touches itself
for (int i = 1; i < snakePointsList.size(); i++){
if (headPositionX == snakePointsList.get(i).getPositionX() &&
headPositionY == snakePointsList.get(i).getPositionY()){
gameOver = true;
break;
}
}
}
return gameOver;
}
private Paint createPointColor(){
if (pointColor == null){
pointColor = new Paint();
pointColor.setColor(snakeColor);
pointColor.setStyle(Paint.Style.FILL);
pointColor.setAntiAlias(true);
}
return pointColor;
}
}
這是我的清單
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.practechs.kubetnew28_05">
<uses-permission android:name="android.permission.INTERNET" />
<application
android:allowBackup="true"
android:exported="false"
android:icon="@mipmap/logo"
android:label="@string/app_name"
android:roundIcon="@mipmap/logo"
android:supportsRtl="true"
android:theme="@style/Theme.KubetNew25_05">
<activity
android:name=".GameActivity"
android:exported="false"
android:theme="@style/Theme.AppCompat.Light.NoActionBar.FullScreen"/>
<activity
android:name=".WebsiteActivity"
android:exported="false" />
<activity
android:name=".HomeActivity"
android:exported="false" />
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
我的 logcat 中顯示的錯誤
2022-06-08 14:21:13.881 19048-19242/com.practechs.kubetnew28_05 E/AndroidRuntime: FATAL EXCEPTION: Timer-0
Process: com.practechs.kubetnew28_05, PID: 19048
java.lang.NullPointerException: Attempt to invoke interface method 'android.graphics.Canvas android.view.SurfaceHolder.lockCanvas()' on a null object reference
at com.practechs.kubetnew28_05.GameActivity$5.run(GameActivity.java:290)
at java.util.TimerThread.mainLoop(Timer.java:562)
at java.util.TimerThread.run(Timer.java:512)
堆棧跟蹤顯示 NPE 發生的方法和行:
...SurfaceHolder.lockCanvas()...
...(GameActivity.java:290)
發生這種情況是因為您的SurfaceHolder
變量為null
,直到您在surfaceCreated
中設置它:
private SurfaceHolder surfaceHolder;
@Override
public void surfaceCreated(@NonNull SurfaceHolder holder) {
this.surfaceHolder = surfaceHolder;
init();
}
這就是問題所在,而不是設置創建的SurfaceHolder
,而是在其自身上設置類變量。 創建的SurfaceHolder
稱為holder而不是surfaceHolder 。
您可以通過重命名方法參數來修復它:
@Override
public void surfaceCreated(@NonNull SurfaceHolder surfaceHolder) {
this.surfaceHolder = surfaceHolder;
init();
}
或正確分配方法參數。
@Override
public void surfaceCreated(@NonNull SurfaceHolder holder) {
this.surfaceHolder = holder;
init();
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.