My app crashes when I put layout.setVisibilty(VISIBLE)
in my checkExit()
method. my FATAL EXCEPTION
crash log tells me its because of a null object reference
. I can't see why, and I don't know how to fix it.
I've tried making layout static in my MainActivity, I've tried making it static in my GameView. I've tried changing where its initialised but I still can't see why it's being thrown.
My MainActivity code:
package com.example.practicingandroidwithsean.mazeone;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.LinearLayout;
public class MainActivity extends AppCompatActivity {
boolean gameIsActive = true;
public void playAgain(View view){
View gameView = findViewById(R.id.gameView);
LinearLayout layout = findViewById(R.id.playAgainLayout);
Animation slideDown = AnimationUtils.loadAnimation(getApplicationContext(), R.anim.slide_down);
Animation slideUp = AnimationUtils.loadAnimation(getApplicationContext(), R.anim.slide_up);
if(gameView.getVisibility() == View.INVISIBLE){
gameIsActive = false;
layout.startAnimation(slideUp);
layout.setVisibility(View.VISIBLE);
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
LinearLayout layout = findViewById(R.id.playAgainLayout);
layout.setVisibility(View.INVISIBLE);
}
}
My GameView code... this is where everything mainly happens:
public class GameView extends View {
public GameView(Context context) {
super(context);
}
private enum Direction{ //data type of self defined constants
UP, DOWN, LEFT, RIGHT
}
private static Cell[][] cells;
public static Cell player, exit, trail;
private static final int COLS = 12, ROWS = 18;
private static final float WALL_THICKNESS = 4;
private static ArrayList<Cell> trailList = new ArrayList<>();
private float cellSize, hMargin, vMargin;
private int counter = 0;
private Paint wallPaint, playerPaint, exitPaint, trailPaint;
private static Random random;
private TextView TextViewTime;
private int seconds, minutes;
private boolean gameIsActive = true;
LinearLayout layout;
View gameView;
public GameView(Context context, AttributeSet attrs) {
super(context, attrs);
wallPaint = new Paint();
wallPaint.setColor(Color.WHITE);
wallPaint.setStrokeWidth(WALL_THICKNESS);
playerPaint = new Paint();
playerPaint.setColor(Color.RED);
exitPaint = new Paint();
exitPaint.setColor(Color.BLUE);
// trailPaint = new Paint();
// trailPaint.setColor(Color.YELLOW);
random = new Random();
this.seconds = 0;
this.minutes = 0;
layout = findViewById(R.id.playAgainLayout);
gameView = findViewById(R.id.gameView);
// timer(findViewById(R.id.Timer));
createMaze();
}
public void createMaze(){
Stack<Cell> stack = new Stack<>();
Cell current, next;
cells = new Cell[COLS][ROWS];
for(int x=0; x<COLS; x++){
for(int y=0; y<ROWS; y++){
cells[x][y] = new Cell(x, y); //2 Dimensional array of cell objects for the whole msze
}
}
player = cells[0][0]; //This is where the player starts
exit = cells[COLS-1][ROWS-1]; //This is the exit
current = cells[0][0];
current.visited = true;
do {
next = getNeighbour(current);
if (next != null) {
removeWall(current, next);
stack.push(current);
current = next;
current.visited = true;
} else
current = stack.pop(); //gives us the top element of the stack and removes it from the
}while(!stack.empty());
Animation slideUp = AnimationUtils.loadAnimation(getContext(), R.anim.slide_up);
gameView.startAnimation(slideUp);
}
public void checkExit() {
if (player == exit && counter < 3) {
counter++;
Animation slideDown = AnimationUtils.loadAnimation(getContext(), R.anim.mazeslidedown);
gameView.startAnimation(slideDown);
gameView.setVisibility(INVISIBLE);
layout.setVisibility(VISIBLE);
}
}
When the player == exit
, the View slides away. This has no problems, but when I try to make the layout.setVisibility(Visible)
to work when player==exit
, the game crashes. Below is the error.
Process: com.example.practicingandroidwithsean.mazeone, PID: 4295
java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.LinearLayout.setVisibility(int)' on a null object reference
at com.example.practicingandroidwithsean.mazeone.GameView.checkExit(GameView.java:285)
at com.example.practicingandroidwithsean.mazeone.GameView.movePlayer(GameView.java:273)
at com.example.practicingandroidwithsean.mazeone.GameView.onTouchEvent(GameView.java:349)
at android.view.View.dispatchTouchEvent(View.java:12540)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3159)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2844)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3159)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2844)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3159)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2844)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3159)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2844)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3159)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2844)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3159)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2844)
at com.android.internal.policy.DecorView.superDispatchTouchEvent(DecorView.java:601)
at com.android.internal.policy.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1871)
at android.app.Activity.dispatchTouchEvent(Activity.java:3384)
at androidx.appcompat.view.WindowCallbackWrapper.dispatchTouchEvent(WindowCallbackWrapper.java:69)
at com.android.internal.policy.DecorView.dispatchTouchEvent(DecorView.java:563)
at android.view.View.dispatchPointerEvent(View.java:12788)
at android.view.ViewRootImpl$ViewPostImeInputStage.processPointerEvent(ViewRootImpl.java:5670)
at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:5465)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4958)
at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:5011)
at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:4977)
at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:5114)
at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:4985)
at android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:5171)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4958)
at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:5011)
at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:4977)
at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:4985)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4958)
at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:7736)
at android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:7676)
at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:7637)
at android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent(ViewRootImpl.java:7847)
at android.view.InputEventReceiver.dispatchInputEvent(InputEventReceiver.java:197)
at android.view.InputEventReceiver.nativeConsumeBatchedInputEvents(Native Method)
at android.view.InputEventReceiver.consumeBatchedInputEvents(InputEventReceiver.java:186)
at android.view.ViewRootImpl.doConsumeBatchedInput(ViewRootImpl.java:7810)
at android.view.ViewRootImpl$ConsumeBatchedInputRunnable.run(ViewRootImpl.java:7874)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:911)
at android.view.Choreographer.doCallbacks(Choreographer.java:723)
at android.view.Choreographer.doFrame(Choreographer.java:652)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:897)
at android.os.Handler.handleCallback(Handler.java:789)
E/AndroidRuntime: at android.os.Handler.dispatchMessage(Handler.java:98)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6944)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:327)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1374)
Application terminated.
The expected results is for the View to slide away, as it does, and then for the playAgainLayout to slide up. This then allows for my playAgain button to work (I'll be creating this in the MainActivity.class). If it helps to know, the activity_main.xml contains a view which is linked to the gameView.
my activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/black"
tools:context=".MainActivity">
<Chronometer
android:id="@+id/chronometer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:layout_marginBottom="8dp"
android:textColor="@android:color/white"
android:textSize="45sp"
app:layout_constraintBottom_toTopOf="@+id/gameView"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<view
android:id="@+id/gameView"
class="com.example.practicingandroidwithsean.mazeone.GameView"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginStart="8dp"
android:layout_marginTop="140dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="8dp"
android:background="@drawable/border"
android:visibility="visible"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.1"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<LinearLayout
android:id="@+id/playAgainLayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="8dp"
android:background="@drawable/border"
android:orientation="vertical"
android:visibility="invisible"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<TextView
android:id="@+id/wellDoneTV"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dp"
android:text="Well Done!"
android:textAlignment="center"
android:textColor="@android:color/white"
android:textSize="50sp" />
<TextView
android:id="@+id/gameTime"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="5dp"
android:text="0:00"
android:textAlignment="center"
android:textColor="@android:color/white"
android:textSize="30sp" />
<Button
android:id="@+id/playAgain"
style="@style/Widget.AppCompat.Button.Colored"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/button_border"
android:onClick="playAgain"
android:text="Button"
android:textColor="@android:color/white"
android:textSize="25sp" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>