地理围栏未显示在地图应用中

时间:2015-11-11 12:54:19

标签: android google-maps google-maps-markers geofencing android-geofence

我正在尝试使用Google Maps API和Geofence API创建一个应用,在地图中的标记中创建一个圆形区域。当用户进入此圆形区域时,他们将在进入或退出时收到提醒通知。

我阅读了我找到的所有教程但无法正常工作,我不知道是什么问题。

CODE:

我创建了一个activity_maps.xml和一个MapsActivity类来控制地图功能并与MapsActivity一起实现地理围栏类,但由于GoogleAPIClient无法连接,因此不会显示地理围栏。我不知道为什么。

activity_maps.xml

<fragment xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:map="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent"
android:layout_height="match_parent" android:id="@+id/map" tools:context=".MapsActivity"
android:name="com.google.android.gms.maps.SupportMapFragment" />

MapsActivity.class

public class MapsActivity extends FragmentActivity implements OnMapReadyCallback, GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, ResultCallback<Status> {

protected static final String TAG = "MapsActivity";
protected GoogleApiClient mGoogleApiClient;
private PendingIntent mGeofencePendingIntent;
private GoogleMap mMap;
protected ArrayList<Geofence> mGeofenceList;
private boolean mGeofencesAdded;
private boolean firstTime = true;
private SharedPreferences mSharedPreferences;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_maps);
    SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map);
    mapFragment.getMapAsync(this);
    mGeofenceList = new ArrayList<Geofence>();
    mGeofencePendingIntent = null;
    mSharedPreferences = getSharedPreferences(Constants.SHARED_PREFERENCES_NAME, MODE_PRIVATE);
    mGeofencesAdded = mSharedPreferences.getBoolean(Constants.GEOFENCES_ADDED_KEY, false);
    populateGeofenceList();
    buildGoogleApiClient();

}

@Override
public void onMapReady(GoogleMap googleMap) {
    mMap = googleMap;
    mMap.setMyLocationEnabled(true);
    if (mMap != null) {

        mMap.setOnMyLocationChangeListener(new GoogleMap.OnMyLocationChangeListener() {
            @Override
            public void onMyLocationChange(Location arg0) {
                // TODO Auto-generated method stub
                if (firstTime) {
                    CameraUpdate cameraUpdate = CameraUpdateFactory.newLatLngZoom(new LatLng(arg0.getLatitude(), arg0.getLongitude()), 18);
                    mMap.animateCamera(cameraUpdate);
                    firstTime = false;
                }

            }
        });
    }
    LatLng NewPointer = new LatLng(-22.9274767,-47.0775973);
    //Drawable iconDrawable = getResources().getDrawable(R.drawable.markernp);
    //Bitmap iconBmp = ((BitmapDrawable) iconDrawable).getBitmap();
    //.icon(BitmapDescriptorFactory.fromBitmap(iconBmp)));
    mMap.addMarker(new MarkerOptions().position(NewPointer).title("Title").snippet("Subtitle"));
    addGeofencesButtonHandler();
}

protected synchronized void buildGoogleApiClient() {
    mGoogleApiClient = new GoogleApiClient.Builder(this)
            .addConnectionCallbacks(this)
            .addOnConnectionFailedListener(this)
            .addApi(LocationServices.API)
            .build();
}

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

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

public void populateGeofenceList() {
    LatLng NewPointer = new LatLng(-22.9274767,-47.0775973);
        mGeofenceList.add(new Geofence.Builder()
                .setRequestId("npGeofence")
                .setCircularRegion(NewPointer.latitude, NewPointer.longitude, 200)
                .setExpirationDuration(Geofence.NEVER_EXPIRE)
                .setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER | Geofence.GEOFENCE_TRANSITION_EXIT)
                .build());
}

private GeofencingRequest getGeofencingRequest() {
    GeofencingRequest.Builder builder = new GeofencingRequest.Builder();
    builder.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER);
    builder.addGeofences(mGeofenceList);
    return builder.build();
}

public void addGeofencesButtonHandler() {
    if (!mGoogleApiClient.isConnected()) {
        Toast.makeText(this, "not connected", Toast.LENGTH_SHORT).show();
        return;
    }

    try {
        LocationServices.GeofencingApi.addGeofences(
                mGoogleApiClient,
                getGeofencingRequest(),
                getGeofencePendingIntent()
        ).setResultCallback(this);
    } catch (SecurityException securityException) {
        logSecurityException(securityException);
    }
}

private void logSecurityException(SecurityException securityException) {
    Log.e(TAG, "Invalid location permission. " +
            "You need to use ACCESS_FINE_LOCATION with geofences", securityException);
}

@Override
public void onConnected(Bundle bundle) {

}

@Override
public void onConnectionSuspended(int i) {

}

@Override
public void onConnectionFailed(ConnectionResult connectionResult) {

}


@Override
public void onResult(Status status) {
    if (status.isSuccess()) {
        mGeofencesAdded = !mGeofencesAdded;
        SharedPreferences.Editor editor = mSharedPreferences.edit();
        editor.putBoolean(Constants.GEOFENCES_ADDED_KEY, mGeofencesAdded);
        editor.apply();
    } else {
        String errorMessage = GeofenceErrorMessages.getErrorString(this,
                status.getStatusCode());
        Log.e(TAG, errorMessage);
    }
}

private PendingIntent getGeofencePendingIntent() {
    if (mGeofencePendingIntent != null) {
        return mGeofencePendingIntent;
    }
    Intent intent = new Intent(this, GeofenceTransitionsIntentService.class);
    return PendingIntent.getService(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
}

Contants.class

public final class Constants {

private Constants() {
}

public static final String PACKAGE_NAME = "com.google.android.gms.location.Geofence";

public static final String SHARED_PREFERENCES_NAME = PACKAGE_NAME + ".SHARED_PREFERENCES_NAME";

public static final String GEOFENCES_ADDED_KEY = PACKAGE_NAME + ".GEOFENCES_ADDED_KEY";

/**
 * Used to set an expiration time for a geofence. After this amount of time Location Services
 * stops tracking the geofence.
 */
public static final long GEOFENCE_EXPIRATION_IN_HOURS = 12;

/**
 * For this sample, geofences expire after twelve hours.
 */
public static final long GEOFENCE_EXPIRATION_IN_MILLISECONDS =
        GEOFENCE_EXPIRATION_IN_HOURS * 60 * 60 * 1000;
public static final float GEOFENCE_RADIUS_IN_METERS = 1609; // 1 mile, 1.6 km

/**
 * Map for storing information about airports in the San Francisco bay area.
 */
public static final HashMap<String, LatLng> BAY_AREA_LANDMARKS = new HashMap<String, LatLng>();
static {
    // San Francisco International Airport.
    BAY_AREA_LANDMARKS.put("SFO", new LatLng(37.621313, -122.378955));

    // Googleplex.
    BAY_AREA_LANDMARKS.put("GOOGLE", new LatLng(37.422611,-122.0840577));
}

GeofenceErrorMessage.class

public class GeofenceErrorMessages {
/**
 * Prevents instantiation.
 */
private GeofenceErrorMessages() {}

/**
 * Returns the error string for a geofencing error code.
 */
public static String getErrorString(Context context, int errorCode) {
    Resources mResources = context.getResources();
    switch (errorCode) {
        case GeofenceStatusCodes.GEOFENCE_NOT_AVAILABLE:
            return "geofence not avaliable";
        case GeofenceStatusCodes.GEOFENCE_TOO_MANY_GEOFENCES:
            return "geofence to many geofences";
        case GeofenceStatusCodes.GEOFENCE_TOO_MANY_PENDING_INTENTS:
            return "geofence to many pending geofences";
        default:
            return "unknown geofence error";
    }
}

GeofenceTransitionIntentService.class

public class GeofenceTransitionsIntentService extends IntentService {

protected static final String TAG = "GeofenceTransitionsIS";

/**
 * This constructor is required, and calls the super IntentService(String)
 * constructor with the name for a worker thread.
 */
public GeofenceTransitionsIntentService() {
    // Use the TAG to name the worker thread.
    super(TAG);
}

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

/**
 * Handles incoming intents.
 * @param intent sent by Location Services. This Intent is provided to Location
 *               Services (inside a PendingIntent) when addGeofences() is called.
 */
@Override
protected void onHandleIntent(Intent intent) {
    GeofencingEvent geofencingEvent = GeofencingEvent.fromIntent(intent);
    if (geofencingEvent.hasError()) {
        String errorMessage = GeofenceErrorMessages.getErrorString(this,
                geofencingEvent.getErrorCode());
        Log.e(TAG, errorMessage);
        return;
    }

    // Get the transition type.
    int geofenceTransition = geofencingEvent.getGeofenceTransition();

    // Test that the reported transition was of interest.
    if (geofenceTransition == Geofence.GEOFENCE_TRANSITION_ENTER ||
            geofenceTransition == Geofence.GEOFENCE_TRANSITION_EXIT) {

        // Get the geofences that were triggered. A single event can trigger multiple geofences.
        List<Geofence> triggeringGeofences = geofencingEvent.getTriggeringGeofences();

        // Get the transition details as a String.
        String geofenceTransitionDetails = getGeofenceTransitionDetails(
                this,
                geofenceTransition,
                triggeringGeofences
        );

        // Send notification and log the transition details.
        sendNotification(geofenceTransitionDetails);
        Log.i(TAG, geofenceTransitionDetails);
    } else {
        // Log the error.
        Log.e(TAG, "genfence transition invalid");
    }
}

/**
 * Gets transition details and returns them as a formatted string.
 *
 * @param context               The app context.
 * @param geofenceTransition    The ID of the geofence transition.
 * @param triggeringGeofences   The geofence(s) triggered.
 * @return                      The transition details formatted as String.
 */
private String getGeofenceTransitionDetails(
        Context context,
        int geofenceTransition,
        List<Geofence> triggeringGeofences) {

    String geofenceTransitionString = getTransitionString(geofenceTransition);

    // Get the Ids of each geofence that was triggered.
    ArrayList triggeringGeofencesIdsList = new ArrayList();
    for (Geofence geofence : triggeringGeofences) {
        triggeringGeofencesIdsList.add(geofence.getRequestId());
    }
    String triggeringGeofencesIdsString = TextUtils.join(", ",  triggeringGeofencesIdsList);

    return geofenceTransitionString + ": " + triggeringGeofencesIdsString;
}

/**
 * Posts a notification in the notification bar when a transition is detected.
 * If the user clicks the notification, control goes to the MainActivity.
 */
private void sendNotification(String notificationDetails) {
    // Create an explicit content Intent that starts the main Activity.
    Intent notificationIntent = new Intent(getApplicationContext(), MapsActivity.class);

    // Construct a task stack.
    TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);

    // Add the main Activity to the task stack as the parent.
    stackBuilder.addParentStack(MapsActivity.class);

    // Push the content Intent onto the stack.
    stackBuilder.addNextIntent(notificationIntent);

    // Get a PendingIntent containing the entire back stack.
    PendingIntent notificationPendingIntent =
            stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);

    // Get a notification builder that's compatible with platform versions >= 4
    NotificationCompat.Builder builder = new NotificationCompat.Builder(this);

    // Define the notification settings.
    builder.setSmallIcon(R.mipmap.ic_launcher)
            // In a real app, you may want to use a library like Volley
            // to decode the Bitmap.
            .setLargeIcon(BitmapFactory.decodeResource(getResources(),
                    R.mipmap.ic_launcher))
            .setColor(Color.RED)
            .setContentTitle(notificationDetails)
            .setContentText("geofence transition notification")
                    .setContentIntent(notificationPendingIntent);

    // Dismiss notification once the user touches it.
    builder.setAutoCancel(true);

    // Get an instance of the Notification manager
    NotificationManager mNotificationManager =
            (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

    // Issue the notification
    mNotificationManager.notify(0, builder.build());
}

/**
 * Maps geofence transition types to their human-readable equivalents.
 *
 * @param transitionType    A transition type constant defined in Geofence
 * @return                  A String indicating the type of transition
 */
private String getTransitionString(int transitionType) {
    switch (transitionType) {
        case Geofence.GEOFENCE_TRANSITION_ENTER:
            return "geofence transition ended";
        case Geofence.GEOFENCE_TRANSITION_EXIT:
            return "genfence transition exited";
        default:
            return "unknows geofence transition";
    }
}

错误是Toast,而消息“Not Connected”

1 个答案:

答案 0 :(得分:0)

在“MapsActivity.class”中的LocationServices.GeofencingApi.addGeofences方法中调用onConnected。这将确保您只在连接GoogleAPIClient时尝试添加地理围栏。