Android 地理围栏未显示在我的地图应用程序中

Android 地理围栏未显示在我的地图应用程序中,android,google-maps,google-maps-markers,geofencing,android-geofence,Android,Google Maps,Google Maps Markers,Geofencing,Android Geofence,我正在尝试使用GoogleMapsAPI和Geofence API创建一个应用程序,在我的地图标记中创建一个圆形区域。当用户进入此圆形区域时,他们将收到通知,在进入或退出时发出警报 我读了所有我找到的教程,但都不能工作,我不知道有什么问题 代码: 我创建了一个activity_maps.xml和一个MapsActivity类来控制map函数,并将geofence类与MapsActivity一起实现,但是geofence不会出现,因为GoogleAppClient无法连接。我不知道为什么 acti

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

我读了所有我找到的教程,但都不能工作,我不知道有什么问题

代码:

我创建了一个activity_maps.xml和一个MapsActivity类来控制map函数,并将geofence类与MapsActivity一起实现,但是geofence不会出现,因为GoogleAppClient无法连接。我不知道为什么

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" />
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";
    }
}
公共类GeofenceTransitionsIntentService扩展了IntentService{
受保护的静态最终字符串标记=“GeoFenceTransitions”;
/**
*此构造函数是必需的,并调用超级IntentService(字符串)
*具有工作线程名称的构造函数。
*/
公共地理围栏TransitionsIntentService(){
//使用标记来命名工作线程。
超级(标签);
}
@凌驾
public void onCreate(){
super.onCreate();
}
/**
*处理传入的意图。
*@param intent由位置服务发送。此intent提供给位置
*调用addGeofences()时的服务(在Pending帐篷内)。
*/
@凌驾
受保护的手部内容无效(意图){
GeofencingEvent GeofencingEvent=GeofencingEvent.fromIntent(intent);
if(geofencingEvent.hasError()){
String errorMessage=GeofenceErrorMessages.getErrorString(此,
geofencingEvent.getErrorCode());
Log.e(标签、错误消息);
返回;
}
//获取转换类型。
int geofenceTransition=geofencingEvent.getGeofenceTransition();
//测试报告的转换是否有意义。
如果(geofenceTransition==Geofence.Geofence\u TRANSITION\u输入||
geofenceTransition==Geofence.Geofence_TRANSITION_EXIT){
//获取已触发的地理围栏。一个事件可以触发多个地理围栏。
List triggeringGeofences=geofencingEvent.getTriggeringGeofences();
//以字符串形式获取转换详细信息。
字符串geofenceTransitionDetails=getGeofenceTransitionDetails(
这
地球围栏过渡,
触发地理围栏
);
//发送通知并记录转换详细信息。
发送通知(geofenceTransitionDetails);
Log.i(标签、geofenceTransitionDetails);
}否则{
//记录错误。
Log.e(标记“genfence转换无效”);
}
}
/**
*获取转换详细信息并将其作为格式化字符串返回。
*
*@param context应用程序上下文。
*@param geofenceTransition地理围栏转换的ID。
*@param triggeringgeofenses已触发geofense。
*@返回格式为字符串的转换详细信息。
*/
私有字符串getGeofenceTransitionDetails(
语境,
int geofenceTransition,
列表触发(地理围栏){
String geofenceTransitionString=getTransitionString(geofenceTransition);
//获取触发的每个地理围栏的ID。
ArrayList triggeringGeofencesIdsList=新建ArrayList();
用于(地理围栏:触发地理围栏){
triggeringgeofinessidslist.add(geofinence.getRequestId());
}
字符串triggeringGeofencesIdsString=TextUtils.join(“,”,triggeringGeofencesIdsList);
返回geofenceTransitionString+”:“+triggeringGeofencesIdsString;
}
/**
*当检测到转换时,在通知栏中发布通知。
*如果用户单击通知,控件将转到MainActivity。
*/
私有void sendNotification(字符串notificationDetails){
//创建启动主活动的明确内容意图。
Intent notificationIntent=新意图(getApplicationContext(),MapsActivity.class);
//构造一个任务堆栈。
TaskStackBuilder stackBuilder=TaskStackBuilder.create(此);
//将主活动作为父活动添加到任务堆栈中。
addParentStack(MapsActivity.class);
//将内容意图推送到堆栈上。
stackBuilder.addNextIntent(通知意图);
//获取一个包含整个后堆栈的悬挂式帐篷。
悬而未决的通知悬而未决的=
stackBuilder.GetPendingEvent(0,PendingEvent.FLAG_UPDATE_CURRENT);
//获取与平台版本>=4兼容的通知生成器
NotificationCompat.Builder=新建NotificationCompat.Builder(此);
//定义通知设置。
builder.setSmallIcon(R.mipmap.ic_启动器)
//在一个真正的应用程序中,你可能想使用像Volley这样的库
//解码位图。
.setLargeIcon(BitmapFactory.decodeResource(getResources()),
R.mipmap.ic_启动器)
.setColor(颜色.红色)
.setContentTitle(通知详细信息)
.setContentText(“地理围栏过渡通知”)
.setContentIntent(通知依赖内容);
//一旦用户触摸到通知,将其关闭。
builder.setAutoCancel(true);
//获取通知管理器的实例
通知经理通知经理=
(NotificationManager)getSystemService(上下文通知服务);
//发出通知
mNotificationManager.notify(0,builder.build());
}
/**
*将地理围栏转换类型映射到其人类可读的等效类型。
*
*@param transitionType在Geofence中定义的转换类型常量
*@返回指示转换类型的字符串
*/
私有字符串getTransitionString(int transitionType){
开关(转换类型){
案例Geopfence.Geopfence\u过渡\u输入:
返回“地理围栏过渡结束”;
案例Geofence.Geofence_过渡_出口:
返回“genfence转换已退出”;
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));
}
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";
    }
}
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";
    }
}