Android back navigation leads to crash on activity based on intent-ThrowExceptions

Exception or error:

I have an android app with three activities A, B, and C. B starts with a necessary intent form A and from B I can startActivity C. But when I use the back button on the action bar to go back from C to B, the app crashes because B received no intent. How to solve this.

Code for Activity B, getting intent from Activity A. It is important to have this intent for the activity B to function.

 @Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_parking_spot);
    getSupportActionBar().hide();
    spot = getIntent().getParcelableExtra("spot");

    init();
}

private void init() {

    days = findViewById(R.id.spot_days);
    rate = findViewById(R.id.spot_rate);
    timing = findViewById(R.id.spot_timing);
    name = findViewById(R.id.spot_name);
    address = findViewById(R.id.spot_address);
    spots = findViewById(R.id.spot_spots);

    // This is where null pointer exception is thrown on accessing spot variable
    name.setText(spot.getName());
    address.setText(spot.getAddress());
    timing.setText(spot.getTiming());

    String temp = getResources().getString(R.string.rs) + " " + spot.getRate() + "/HR";
    rate.setText(temp);

    temp = spot.getDays();
    for (int i = 0; i < temp.length(); i++) {
        if (temp.charAt(i) == 'T') {
            setDay(i);
        }
    }

    FirebaseDatabase.getInstance().getReference(spot.getPath()).child("spots").addValueEventListener(new ValueEventListener() {
        @Override
        public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
            long total = dataSnapshot.getChildrenCount(), free = 0;
            for (DataSnapshot shot : dataSnapshot.getChildren()) {
                Log.v("Spot", shot.child("status").getValue(Integer.class) + "");
                if (shot.child("status").getValue(Integer.class) == 0) {

                    free++;
                }
            }
            String temp = free + "/" + total;
            spots.setText(temp);

        }

        @Override
        public void onCancelled(@NonNull DatabaseError databaseError) {

        }
    });

    findViewById(R.id.navigate_spot).setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Uri gmmIntentUri = Uri.parse("google.navigation:q=" + spot);
            Intent mapIntent = new Intent(Intent.ACTION_VIEW, gmmIntentUri);
            mapIntent.setPackage("com.google.android.apps.maps");
            if (mapIntent.resolveActivity(getPackageManager()) != null) {
                startActivity(mapIntent);
            }
        }
    });

    findViewById(R.id.book_now).setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Intent intent = new Intent(ParkingSpotActivity.this, BookingActivity.class);
            intent.putExtra("spot", spot);
            startActivity(intent);
        }
    });

    setupSlider();
}

Going to C from B

 confirm.setOnClickListener(v -> {
        Intent intent = new Intent(getApplicationContext(), CheckoutActivity.class);
        intent.putExtra("spot", parkingSpot);
        intent.putExtra("pos", pos);
        startActivity(intent);
    });

Now app has opened activity C. Clicking on the back arrow icon in Activity B to C leads to an error as B loses its intent data

Activity B

Activity C

Erro from debugger when i press back button

E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.mobile.solutions.parking, PID: 26598
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.mobile.solutions.parking/com.mobile.solutions.parking.activity.ParkingSpotActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String com.mobile.solutions.parking.model.ParkingSpot.getName()' on a null object reference
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3374)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3513)
    at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:83)
    at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
    at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2109)
    at android.os.Handler.dispatchMessage(Handler.java:107)
    at android.os.Looper.loop(Looper.java:214)
    at android.app.ActivityThread.main(ActivityThread.java:7682)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:516)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:950)
 Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String com.mobile.solutions.parking.model.ParkingSpot.getName()' on a null object reference
    at com.mobile.solutions.parking.activity.ParkingSpotActivity.init(ParkingSpotActivity.java:59)
    at com.mobile.solutions.parking.activity.ParkingSpotActivity.onCreate(ParkingSpotActivity.java:47)
    at android.app.Activity.performCreate(Activity.java:7815)
    at android.app.Activity.performCreate(Activity.java:7804)
    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1318)
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3349)

The only point is that B to C works fine but not vice versa. This I think is because B doesn’t retain its intent data

How to solve:

In the OnCreate method add this:

if (getSupportActionBar() != null)
{
    getSupportActionBar().setDisplayHomeAsUpEnabled(true);
}

Then add this method:

@Override
public boolean onSupportNavigateUp() {
    onBackPressed();
    return true;
}

###

put below the line of code into Activity B onCreate() where you fetch your intent data

if(getIntent()!=null){
   //your intent code
}

THAT’S IT 😉

###

You can use MVVM, Moxy MVP structure or savedInstance to store your data and use it. When you back from C to B it will use one of this data store algorithm and you will not get crashed. So, check every time

if (savedInstance != null ){
    spot = savedInstance.getParcelable("spot");
} else {
    spot = getIntent().getParcelableExtra("spot");
}

Leave a Reply

Your email address will not be published. Required fields are marked *