0

I have a route tracking app that uses GoogleMaps and Location Services. And everything worked fine until yesterday that my app crash every time with a NullPointerException and i don't know why, i haven't changed anything in the code. Here's the code:

package com.example.rocketron.mapa.Activities;


import android.location.Location;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.View;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Toast;

import com.example.rocketron.mapa.R;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.location.LocationListener;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationServices;
import com.google.android.gms.maps.CameraUpdate;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.MapView;
import com.google.android.gms.common.api.GoogleApiClient.ConnectionCallbacks;
import com.google.android.gms.common.api.GoogleApiClient.OnConnectionFailedListener;
import com.google.android.gms.maps.OnMapReadyCallback;
import com.google.android.gms.maps.model.BitmapDescriptorFactory;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.MarkerOptions;

public class MainActivity extends AppCompatActivity implements ConnectionCallbacks,
        OnConnectionFailedListener, LocationListener, OnMapReadyCallback {

    protected static final String TAG = "location-updates-sample";

    // Keys for storing activity state in the Bundle.
    protected final static String REQUESTING_LOCATION_UPDATES_KEY = "requesting-location-updates-key";
    protected final static String LOCATION_KEY = "location-key";

    //UI Elements
    protected Toolbar toolbar;
    protected FloatingActionButton fab;
    protected GoogleMap googleMap;
    protected MapView mapView;

    //Provides the entry point to Google Play services.
    protected GoogleApiClient mGoogleApiClient;

    //Stores parameters for requests to the FusedLocationProviderApi.
    protected LocationRequest mLocationRequest;

    //Represents a geographical location.
    protected Location mCurrentLocation;

    //Tracks the status of the location updates request. Value changes when the user presses the
    //Start Updates and Stop Updates button.
    protected boolean mRequestingLocationUpdates;

    protected double latitude;
    protected double longitude;
    protected LatLng mLatLng;
    protected CameraUpdate cameraUpdate;
    Marker currentMarker;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        toolbar = (Toolbar) findViewById(R.id.appbar);
        setSupportActionBar(toolbar);

        fab = (FloatingActionButton) findViewById(R.id.fab);

        mapView = (MapView) findViewById(R.id.mi_mapa);
        mapView.getMapAsync(this);
        mapView.onCreate(savedInstanceState);

        mRequestingLocationUpdates = false;
        updateValuesFromBundle(savedInstanceState);

        buildGoogleApiClient();

        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                togglePeriodicLocationUpdates();
            }
        });
    }

    @Override
    public void onMapReady(GoogleMap map) {
        googleMap = map;
        googleMap.getUiSettings().setMapToolbarEnabled(false); //Hide Map Toolbar when marker is clicked
    }

    @Override
    protected void onStart() {
        mGoogleApiClient.connect();
        super.onStart();
    }

    @Override
    protected void onResume() {
        super.onResume();
        mapView.onResume();
        if (mGoogleApiClient.isConnected() && mRequestingLocationUpdates) {
            startLocationUpdates();
        }
    }

    @Override
    protected void onPause() {
        super.onPause();
        mapView.onPause();
        if (mGoogleApiClient.isConnected()) {
            stopLocationUpdates();
        }
    }

    @Override
    protected void onStop() {
        mGoogleApiClient.disconnect();
        super.onStop();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mapView.onDestroy();
    }

    /**
     * Updates fields based on data stored in the bundle.
     *
     * @param savedInstanceState The activity state saved in the Bundle.
     */
    private void updateValuesFromBundle(Bundle savedInstanceState) {
        Log.i(TAG, "Updating values from bundle");
        if (savedInstanceState != null) {
            // Update the value of mRequestingLocationUpdates from the Bundle, and make sure that
            // the Start Updates and Stop Updates buttons are correctly enabled or disabled.
            if (savedInstanceState.keySet().contains(REQUESTING_LOCATION_UPDATES_KEY)) {
                mRequestingLocationUpdates = savedInstanceState.getBoolean(
                        REQUESTING_LOCATION_UPDATES_KEY);
                setFabEnabledState();
            }

            // Update the value of mCurrentLocation from the Bundle and update the UI to show the
            // correct latitude and longitude.
            if (savedInstanceState.keySet().contains(LOCATION_KEY)) {
                // Since LOCATION_KEY was found in the Bundle, we can be sure that mCurrentLocation
                // is not null.
                mCurrentLocation = savedInstanceState.getParcelable(LOCATION_KEY);
            }

            updateUI();
        }
    }

    /*------------- Build Google API Client ----------------*/
    protected synchronized void buildGoogleApiClient() {
        Log.i(TAG, "Building GoogleApiClient");
        mGoogleApiClient = new GoogleApiClient.Builder(this)
                .addConnectionCallbacks(this)
                .addOnConnectionFailedListener(this)
                .addApi(LocationServices.API)
                .build();
        createLocationRequest();
    }

    /*------------- Set Up a Location Request -----------------*/
    protected void createLocationRequest() {
        mLocationRequest = new LocationRequest();
        mLocationRequest.setInterval(5000);
        mLocationRequest.setFastestInterval(1000);
        mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
    }

    protected void updateUI() {
        if (currentMarker != null)
            currentMarker.remove();
        latitude = mCurrentLocation.getLatitude();
        longitude = mCurrentLocation.getLongitude();
        mLatLng = new LatLng(latitude, longitude);
        cameraUpdate = CameraUpdateFactory.newLatLng(mLatLng);
        googleMap.moveCamera(cameraUpdate);
        currentMarker = googleMap.addMarker(new MarkerOptions()
                .position(mLatLng)
                .title(String.format("%f, %f", latitude, longitude))
                .icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_ORANGE)));
    }

    private void togglePeriodicLocationUpdates() {
        if (!mRequestingLocationUpdates) {
            // Changing the fab button
            mRequestingLocationUpdates = true;
            setFabEnabledState();
            getSupportActionBar().hide();
            // Starting the location updates
            startLocationUpdates();

        } else {
            // Changing the fab button
            mRequestingLocationUpdates = false;
            setFabEnabledState();
            getSupportActionBar().show();
            // Stopping the location updates
            stopLocationUpdates();

        }
    }

    private void setFabEnabledState() {
        if (mRequestingLocationUpdates) {
            fab.setImageDrawable(ContextCompat.getDrawable(this, R.drawable.ic_stop_white_24dp));
        } else {
            fab.setImageDrawable(ContextCompat.getDrawable(this, R.drawable.ic_play_arrow_white_24dp));
        }
    }

    protected void startLocationUpdates() {

        LocationServices.FusedLocationApi.requestLocationUpdates(
                mGoogleApiClient, mLocationRequest, this);

    }

    protected void stopLocationUpdates() {
        LocationServices.FusedLocationApi.removeLocationUpdates(
                mGoogleApiClient, this);
    }

    /*-------------Override Methods from ConnectionCallbacks, OnConnectionFailedListener-------------*/
    @Override
    public void onConnected(Bundle bundle) {
        Log.i(TAG, "Connected to GoogleApiClient");
        if (mCurrentLocation == null) {
            mCurrentLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
            updateUI();
        }

        if (mRequestingLocationUpdates) {
            startLocationUpdates();
        }
    }

    @Override
    public void onConnectionSuspended(int i) {
        // The connection to Google Play services was lost for some reason. We call connect() to
        // attempt to re-establish the connection.
        Log.i(TAG, "Connection suspended");
        mGoogleApiClient.connect();
    }

    @Override
    public void onConnectionFailed(ConnectionResult connectionResult) {
        // Refer to the javadoc for ConnectionResult to see what error codes might be returned in
        // onConnectionFailed.
        Log.i(TAG, "Connection failed: ConnectionResult.getErrorCode() = " + connectionResult.getErrorCode());
    }

    /*----------------Override Methods from LocationListener ----------------------*/
    @Override
    public void onLocationChanged(Location location) {
        mCurrentLocation = location;
        updateUI();
        Toast.makeText(this, getResources().getString(R.string.location_updated_message), Toast.LENGTH_SHORT).show();
    }


    /*------------------Stores activity data in the Bundle.--------------------*/
    public void onSaveInstanceState(Bundle savedInstanceState) {
        savedInstanceState.putBoolean(REQUESTING_LOCATION_UPDATES_KEY, mRequestingLocationUpdates);
        savedInstanceState.putParcelable(LOCATION_KEY, mCurrentLocation);
        super.onSaveInstanceState(savedInstanceState);
    }

    /*----------------Toolbar Methods---------------*/
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }
}

And the error:

02-15 07:02:47.675 13898-13898/com.example.rocketron.mapa 

E/AndroidRuntime: FATAL EXCEPTION: main
java.lang.NullPointerException
at com.example.rocketron.mapa.Activities.MainActivity.updateUI(MainActivity.java:187)
at com.example.rocketron.mapa.Activities.MainActivity.onConnected(MainActivity.java:244)
at com.google.android.gms.common.internal.zzk.zzk(Unknown Source)
at com.google.android.gms.internal.zzmg.zzi(Unknown Source)
at com.google.android.gms.internal.zzme.zzpi(Unknown Source)
at com.google.android.gms.internal.zzme.onConnected(Unknown Source)
at com.google.android.gms.internal.zzmi.onConnected(Unknown Source)
at com.google.android.gms.internal.zzlz.onConnected(Unknown Source)
at com.google.android.gms.common.internal.zzj$zzg.zzqv(Unknown Source)
at com.google.android.gms.common.internal.zzj$zza.zzc(Unknown Source)
at com.google.android.gms.common.internal.zzj$zza.zzv(Unknown Source)
at com.google.android.gms.common.internal.zzj$zzc.zzqx(Unknown Source)
at com.google.android.gms.common.internal.zzj$zzb.handleMessage(Unknown Source)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4867)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1007)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:774)
at dalvik.system.NativeStart.main(Native Method)
DevSolar
  • 67,862
  • 21
  • 134
  • 209
Rocketron
  • 3
  • 3

1 Answers1

0

It looks like your mCurrentLocation is null. This line is the problem mCurrentLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);. The getLastLocation does not get the last known location. You may want to look at this thread for a possible solution.

The fused location provider will only maintain background location if at least one client is connected to it. Now just turning on the location service will not gurranty to store the last known location.

Once the first client connects, it will immediately try to get a location. If your activity is the first client to connect and getLastLocation() is invoked right away in onConnected(), that might not be enough time for the first location to arrive..

Then you are setting mLocationRequest.setFastestInterval(30000); which basically means 30 seconds. so at least 30 seconds after and generally according to your setting preferred time is 120 secs, isn't it a very long time if there is no stored last known location at all? plus you are setting battery balanced priority, which will make you waiting longer time.

mLocationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);

I suggest you to launch Maps app first, so that there is at least some confirmed location and then test your app.

Also, double check if you have your GPS enabled. You may put a checker whether your GPS is on/off. See this thread.

Community
  • 1
  • 1
gerardnimo
  • 1,444
  • 8
  • 10
  • And where do you think i should put my getLastLocation()? I tested and it looks like you are right, thank you for your help – Rocketron Feb 17 '16 at 05:37