Search code examples
androidgoogle-mapsandroid-fragmentsandroid-fragmentactivitygoogle-api-client

Error in Google Map API inside Navigation Bar Fragments


I am trying to build an app with Navigation bar and Google Map API in it.

I followed both of these:

http://www.androidhive.info/2015/04/android-getting-started-with-material-design/

http://blog.teamtreehouse.com/beginners-guide-location-android

tutorial and when I put the map tutorial into one of the fragment inside the navigation bar I'm getting these error:

myGoogleApiClient = new GoogleApiClient.Builder(this)
            .addConnectionCallbacks(this)
            .addOnConnectionFailedListener(this)
            .addApi(LocationServices.API)
            .build();

The error is in the "this" inside the Builder.

This is my complete class code:

package com.clark.androbotics.projectapp;

import android.app.Activity;
import android.content.IntentSender;
import android.location.Location;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

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.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.UiSettings;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.MarkerOptions;

public class MapFragment extends Fragment implements
    GoogleApiClient.ConnectionCallbacks,
    GoogleApiClient.OnConnectionFailedListener,
    LocationListener {

public static final String TAG = MapFragment.class.getSimpleName();

private final static int CONNECTION_FAILURE_RESOLUTION_REQUEST = 9000;

private GoogleApiClient myGoogleApiClient;
private LocationRequest myLocationRequest;

private GoogleMap mMap; // Might be null if Google Play services APK is not available.

public MapFragment() {
    // Required empty public constructor
}

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setUpMapIfNeeded();

    myGoogleApiClient = new GoogleApiClient.Builder(this)
            .addConnectionCallbacks(this)
            .addOnConnectionFailedListener(this)
            .addApi(LocationServices.API)
            .build();

    // Create the LocationRequest object
    myLocationRequest = LocationRequest.create()
            .setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
            .setInterval(10 * 1000)         // 10 seconds, in milliseconds
            .setFastestInterval(1 * 1000);  // 1 second, in milliseconds

}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    View rootView = inflater.inflate(R.layout.fragment_map, container, false);

    // Inflate the layout for this fragment
    return rootView;
}

@Override
public void onResume() {
    super.onResume();
    setUpMapIfNeeded();

    myGoogleApiClient.connect();
}

@Override
public void onPause() {
    super.onPause();
    if (myGoogleApiClient.isConnected()) {
        LocationServices.FusedLocationApi.removeLocationUpdates(myGoogleApiClient, this);
        myGoogleApiClient.disconnect();
    }
}

/**
 * Sets up the map if it is possible to do so (i.e., the Google Play services APK is correctly
 * installed) and the map has not already been instantiated.. This will ensure that we only ever
 * call {@link #setUpMap()} once when {@link #mMap} is not null.
 * <p/>
 * If it isn't installed {@link com.google.android.gms.maps.SupportMapFragment} (and
 * {@link com.google.android.gms.maps.MapView MapView}) will show a prompt for the user to
 * install/update the Google Play services APK on their device.
 * <p/>
 * A user can return to this FragmentActivity after following the prompt and correctly
 * installing/updating/enabling the Google Play services. Since the FragmentActivity may not
 * have been completely destroyed during this process (it is likely that it would only be
 * stopped or paused), {@link #onCreate(Bundle)} may not be called again so we should call this
 * method in {@link #onResume()} to guarantee that it will be called.
 */
private void setUpMapIfNeeded() {
    // Do a null check to confirm that we have not already instantiated the map.
    if (mMap == null) {
        // Try to obtain the map from the SupportMapFragment.
        mMap = ((SupportMapFragment) getFragmentManager().findFragmentById(R.id.map))
                .getMap();
        // Check if we were successful in obtaining the map.
        if (mMap != null) {
            setUpMap();
        }
    }
}

/**
 * This is where we can add markers or lines, add listeners or move the camera. In this case, we
 * just add a marker near Africa.
 * <p/>
 * This should only be called once and when we are sure that {@link #mMap} is not null.
 */
private void setUpMap() {
    UiSettings mapSettings;
    mapSettings = mMap.getUiSettings();

    mapSettings.setZoomControlsEnabled(true);

    mMap.setMapType(GoogleMap.MAP_TYPE_HYBRID);
}

private void handleNewLocation(Location myLocation) {
    double currentLatitude = myLocation.getLatitude();
    double currentLongitude = myLocation.getLongitude();
    LatLng latLng = new LatLng(currentLatitude, currentLongitude);

    MarkerOptions options = new MarkerOptions().position(latLng).title("I am here!");
    mMap.addMarker(options);
    mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(latLng, 17));
}

@Override
public void onAttach(Activity activity) {
    super.onAttach(activity);
}

@Override
public void onDetach() {
    super.onDetach();
}

@Override
public void onConnected(Bundle bundle) {
    Location myLocation = LocationServices.FusedLocationApi.getLastLocation(myGoogleApiClient);

    if (myLocation == null) {
        LocationServices.FusedLocationApi.requestLocationUpdates(myGoogleApiClient, myLocationRequest, this);
    }
    else {
        handleNewLocation(myLocation);
    };
}

@Override
public void onConnectionSuspended(int i) {

}

@Override
public void onLocationChanged(Location location) {

}

@Override
public void onConnectionFailed(ConnectionResult connectionResult) {
    if (connectionResult.hasResolution()) {
        try {
            // Start an Activity that tries to resolve the error
            connectionResult.startResolutionForResult(this, CONNECTION_FAILURE_RESOLUTION_REQUEST);
        } catch (IntentSender.SendIntentException e) {
            e.printStackTrace();
        }
    } else {
        Log.i(TAG, "Location services connection failed with code " + connectionResult.getErrorCode());
    }

}
}

I believe I added the necessary imports, but I can't seem to fix it.

I'm new to Android Development, so I'm not really quite sure what seems to be the problem.

EDIT: The app runs but force closed whenever I go to this fragment.

Seems like there's an error about null object reference.

Here's my logcat:

    05-08 15:42:20.468  24080-24080/com.clark.androbotics.projectapp E/AndroidRuntime﹕ FATAL EXCEPTION: main
Process: com.clark.androbotics.projectapp, PID: 24080
java.lang.NullPointerException: Attempt to invoke virtual method 'com.google.android.gms.maps.GoogleMap com.google.android.gms.maps.SupportMapFragment.getMap()' on a null object reference
        at com.clark.androbotics.projectapp.MapFragment.setUpMapIfNeeded(MapFragment.java:108)
        at com.clark.androbotics.projectapp.MapFragment.onCreate(MapFragment.java:46)
        at android.support.v4.app.Fragment.performCreate(Fragment.java:1763)
        at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:915)
        at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1136)
        at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:739)
        at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1499)
        at android.support.v4.app.FragmentManagerImpl$1.run(FragmentManager.java:456)
        at android.os.Handler.handleCallback(Handler.java:739)
        at android.os.Handler.dispatchMessage(Handler.java:95)
        at android.os.Looper.loop(Looper.java:135)
        at android.app.ActivityThread.main(ActivityThread.java:5293)
        at java.lang.reflect.Method.invoke(Native Method)
        at java.lang.reflect.Method.invoke(Method.java:372)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:904)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:699)

I've believe it was something about .getMap on the fragment, but I'm not sure. Also I've tried putting it in the OnCreateView, but I still have the same error.

Any help is very much appreciated.


Solution

  • The GoogleApiClient.Builder constructor takes a Context such as an Activity, Service, etc, but you are passing this which in this case is a Fragment (which doesn't extend Context).

    Instead, you pass in getActivity(), which returns the Activity the fragment is currently attached to:

    myGoogleApiClient = new GoogleApiClient.Builder(getActivity())
            .addConnectionCallbacks(this)
            .addOnConnectionFailedListener(this)
            .addApi(LocationServices.API)
            .build();