Skip to content

Files

Latest commit

63c79d8 · Dec 26, 2021

History

History
713 lines (525 loc) · 29.9 KB

File metadata and controls

713 lines (525 loc) · 29.9 KB

十三、获取位置和使用地理围栏

在本章中,我们将涵盖以下主题:

  • 如何找到最后一个位置
  • 解决谷歌客户端 OnConnectionFailedListener 报告的问题
  • 如何接收位置更新
  • 创建和监控地理围栏

简介

位置感知为应用提供了许多好处,事实上如此之多,以至于现在即使是桌面应用也试图获得用户的位置。位置使用的范围从逐个转弯的方向,“查找最近的”应用,基于位置的警报,现在甚至有基于位置的游戏,让你用你的设备出去探索。

谷歌应用编程接口为创建位置感知应用和地图功能提供了许多丰富的功能。我们的第一个食谱如何获得最后一个位置将着眼于获得存储在设备上的最后一个已知位置。如果您的应用不是位置密集型的,这可能会提供一种理想的方法来获取用户的位置,而不会产生大量的资源开销。如果您需要持续更新,请转到如何接收位置更新食谱。虽然不断的位置更新需要更多的资源,但是用户很可能理解你何时给他们一个又一个的方向。如果您正在请求邻近位置的位置更新,请查看使用地理围栏选项,在创建和监控地理围栏配方中。

本章中的所有食谱都使用谷歌图书馆。如果您还没有下载软件开发工具包,请按照谷歌的说明进行操作。

类型

添加 SDK 包

既然你已经知道了位置,很有可能你也想绘制地图。这是谷歌使用谷歌地图应用编程接口在安卓上非常容易做到的另一个领域。要开始使用谷歌地图,在安卓工作室创建新项目时,看一下谷歌地图活动选项。不像我们通常对这些食谱做的那样选择空白活动,而是选择谷歌地图活动,如下图所示:

Introduction

最后一个位置怎么走

我们将从一个通常需要的简单方法开始这一章:如何获得最后一个已知的位置。这是一种使用 API 的简单方法,几乎没有额外的资源消耗。(这意味着,你的应用不会负责杀死电池。)

这个食谱也提供了一个很好的设置谷歌定位应用编程接口的介绍。

做好准备

在 Android Studio 中创建新的项目,并将其称为:GetLastLocation。使用默认的电话&平板选项,当提示输入活动类型时,选择空活动

怎么做...

首先,我们将向安卓清单添加必要的权限,然后我们将创建一个带有ButtonTextView元素的布局。最后,我们将创建一个GoogleAPIClient应用编程接口来访问最后一个位置。打开安卓清单,按照以下步骤操作:

  1. 添加以下权限:

    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
  2. Under the Gradle Scripts section, open the build.gradle (Module: app) file, as shown in this screenshot:

    How to do it...

  3. dependencies部分增加以下语句:

    compile 'com.google.android.gms:play-services:8.4.0'
  4. 打开 activity_main.xml,用以下 XML 替换现有的【T1:

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Get Location"
        android:layout_centerInParent="true"
        android:onClick="getLocation"/>
  5. 打开MainActivity.java并添加以下全局变量:

    GoogleApiClient mGoogleApiClient;
    TextView mTextView;
    Button mButton;
  6. ConnectionCallbacks添加类别:

    GoogleApiClient.ConnectionCallbacks mConnectionCallbacks = new GoogleApiClient.ConnectionCallbacks() {
        @Override
        public void onConnected(Bundle bundle) {
            mButton.setEnabled(true);
        }
        @Override
        public void onConnectionSuspended(int i) {}
    };
  7. 添加类来处理OnConnectionFailedListener回调:

    GoogleApiClient.OnConnectionFailedListener mOnConnectionFailedListener = new GoogleApiClient.OnConnectionFailedListener() {
        @Override
        public void onConnectionFailed(ConnectionResult connectionResult) {
            Toast.makeText(MainActivity.this, connectionResult.toString(), Toast.LENGTH_LONG).show();
        }
    };
  8. 将以下代码添加到现有的onCreate()方法中:

    mTextView = (TextView) findViewById(R.id.textView);
    mButton = (Button) findViewById(R.id.button);
    mButton.setEnabled(false);
    setupGoogleApiClient();
  9. 添加设置GoogleAPIClient的方法:

    protected synchronized void setupGoogleApiClient() {
        mGoogleApiClient = new GoogleApiClient.Builder(this)
            .addConnectionCallbacks(mConnectionCallbacks)
            .addOnConnectionFailedListener(mOnConnectionFailedListener)
            .addApi(LocationServices.API)
            .build();
        mGoogleApiClient.connect();
    }
  10. 为按钮点击添加以下方法:

```java
public void getLocation(View view) {
    try {
        Location lastLocation = LocationServices.FusedLocationApi.getLastLocation(
            mGoogleApiClient);
        if (lastLocation != null) {
            mTextView.setText(
                DateFormat.getTimeInstance().format(lastLocation.getTime()) + "\n" + "Latitude="+lastLocation.getLatitude() + "\n" + "Longitude=" + lastLocation.getLongitude());
        } else {
            Toast.makeText(MainActivity.this, "null", Toast.LENGTH_LONG).show();
        }
    }
    catch (SecurityException e) {e.printStackTrace();}
}
```
  1. 您已经准备好在设备或模拟器上运行应用。

它是如何工作的...

在调用getLastLocation()方法之前,我们需要设置GoogleApiClient。我们在我们的setupGoogleApiClient()方法中调用GoogleApiClient.Builder方法,然后连接到库。当图书馆准备好了,它就调用我们的ConnectionCallbacks.onConnected()方法。出于演示目的,这是我们启用按钮的地方。(我们将在后面的菜谱中使用这个回调来启动其他功能。)

我们使用了按钮来显示我们可以按需调用getLastLocation();这不是一次性的电话。系统负责更新位置,并可能在重复呼叫时返回相同的最后位置。(这可以在时间戳中看到——它是位置时间戳,而不是按下按钮时的时间戳。)

这种按需调用位置的方法在应用中发生某些事情(例如对对象进行地理编码)时只需要位置的情况下非常有用。由于系统负责位置更新,因此您的应用不会因位置更新而耗尽电池。

我们收到的位置对象的准确性基于我们的权限设置。我们使用了ACCESS_COARSE_LOCATION,但是如果我们想要更高的精度,我们可以改为请求ACCESS_FINE_LOCATION,并获得以下权限:

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>

最后,为了保持代码集中在GoogleApiClient上,我们只需用SecurityException包装getLastLocation()。在生产应用中,您应该检查并请求权限,如前一章所示。(参见新的运行时权限模型。)

还有更多...

如果连接到GoogleApiClient时出现问题,则调用OnConnectionFailedListener。在这个例子中,我们显示了一个吐司。下一个方法是解决谷歌客户端 OnConnectionFailedListener 报告的问题,这将展示一种更稳健的方法来处理这种情况。

测试位置可能是一个挑战,因为在测试和调试时很难真正移动设备。幸运的是,我们有能力用模拟器模拟全球定位系统数据。(也可以在物理设备上创建模拟位置,但并不容易。)

模拟地点

有三种方法可以用模拟器模拟位置:

  • Android Studio
  • DDMS
  • 通过远程登录的Geo命令

要在安卓工作室中设置模拟位置,请按照以下步骤操作:

  1. 导航至工具 | 安卓 | 安卓设备监视器
  2. 在设备窗口中选择仿真器控制选项卡。
  3. 位置控制下输入全球定位系统坐标。

以下是显示位置 控件的截图:

Mock locations

类型

并不是说通过发送全球定位系统数据来模拟位置。因此,要让你的应用接收模拟位置,它需要接收全球定位系统数据。测试lastLocation()可能不会发送模拟全球定位系统数据,因为它不仅仅依赖全球定位系统来确定设备位置。使用配方尝试模拟位置如何接收位置更新,在那里我们可以请求优先级。(我们不能强制系统使用任何特定的位置传感器,我们只能提出请求。系统将选择最佳解决方案来交付结果。)

另见

解决谷歌客户端 OnConnectionFailedListener 报告的问题

随着谷歌应用接口性质的不断变化,你的用户可能会试图使用你的应用,但由于他们的文件已经过期,他们无法使用。在前面的例子中,我们只是展示了一个吐司,但是我们可以做得更好。我们可以使用GoogleApiAvailability库显示一个对话框,帮助用户解决问题。

我们将继续前面的配方,并向onConnectionFailed()回调添加代码。我们将使用错误结果向用户显示附加信息来解决他们的问题。

做好准备

本食谱将从之前的食谱继续,如何获得最后的位置。如果是从下载的源文件加载项目,则称为HandleGoogleAPIError

怎么做...

由于我们是从前面的配方继续,我们将只介绍更新前面代码所需的步骤。打开ActivityMain.java并按照以下步骤操作:

  1. 向全局类变量添加以下行:

    private final int REQUEST_RESOLVE_GOOGLE_CLIENT_ERROR=1;
    boolean mResolvingError;
  2. 添加以下方法显示谷歌应用编程接口错误对话框:

    private void showGoogleAPIErrorDialog(int errorCode) {
      GoogleApiAvailability googleApiAvailability = GoogleApiAvailability.getInstance();
      Dialog errorDialog = googleApiAvailability.getErrorDialog(this, errorCode, REQUEST_RESOLVE_GOOGLE_CLIENT_ERROR);
      errorDialog.show();
    }
  3. 添加以下代码以覆盖onActivityResult() :

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
      if (requestCode == REQUEST_RESOLVE_GOOGLE_CLIENT_ERROR) {
        mResolvingError = false;
        if (resultCode == RESULT_OK && !mGoogleApiClient.isConnecting() && !mGoogleApiClient.isConnected()) {
            mGoogleApiClient.connect();
        }
      }
    }
  4. onConnectionFailed()中,替换调用 Toast 的现有代码行,使用以下代码:

    if (mResolvingError) {
      return;
    } else if (connectionResult.hasResolution()) {
      mResolvingError = true;
      try {
        connectionResult.startResolutionForResult(MainActivity.this, REQUEST_RESOLVE_GOOGLE_CLIENT_ERROR);
      } catch (IntentSender.SendIntentException e) {
        mGoogleApiClient.connect();
      }
    } else {
      showGoogleAPIErrorDialog(connectionResult.getErrorCode());
    }
  5. 您已经准备好在设备或模拟器上运行应用。

它是如何工作的...

我们现在检查connectionResult看看我们能做什么,而不是像以前那样用 Toast 显示错误信息。GoogleAPIClientconnectionResult表示可能的行动路线。我们可以称之为hasResolution()方法,如下:

connectionResult.hasResolution()

如果响应是 true,那么就是用户可以解决的事情,比如启用定位服务。如果响应是false,我们得到一个GoogleApiAvailability的实例,并调用getErrorDialog()方法。完成后,我们的onActivityResult()回调被调用,在那里我们重置mResolvingError,如果成功,尝试重新连接。

类型

如果您没有使用旧版本谷歌应用编程接口进行测试的设备,您可以尝试在使用旧版本谷歌应用编程接口的仿真器上进行测试。

还有更多...

如果您的应用正在使用片段,您可以使用下面的代码获得一个对话框片段:

ErrorDialogFragment errorFragment = new ErrorDialogFragment();
Bundle args = new Bundle();
args.putInt("dialog_error", errorCode);
errorFragment.setArguments(args);
errorFragment.show(getSupportFragmentManager(), "errordialog");

另见

如何接收位置更新

如果您的应用需要频繁的位置更新,您的应用可以请求定期更新。该配方将使用GoogleApiClient中的requestLocationUpdates()方法进行演示。

做好准备

在 Android Studio 中创建新项目,并将其称为:LocationUpdates。使用默认的电话&平板电脑选项,当提示输入活动类型时,选择空活动

怎么做...

由于我们正在从系统接收更新,我们不需要这个食谱的按钮。我们的布局将只包括TextView来查看位置数据。打开安卓清单,按照以下步骤操作:

  1. 添加以下权限:

    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
  2. 打开文件build.gradle (Module: app)并在dependencies部分添加以下语句:

    compile 'com.google.android.gms:play-services:8.4.0'
  3. 打开activity_main.xml并用以下 XML 替换现有的【T1:

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
  4. 打开MainActivity.java并添加以下全局变量:

    GoogleApiClient mGoogleApiClient;
    LocationRequest mLocationRequest;
    TextView mTextView;
  5. 创建以下LocationListener类:

    LocationListener  mLocationListener = new LocationListener() {
        @Override
        public void onLocationChanged(Location location) {
            if (location != null) {
                mTextView.setText(
                    DateFormat.getTimeInstance().format(location.getTime()) + "\n" + "Latitude="+location.getLatitude()+"\n" + "Longitude="+location.getLongitude());
            }
        }
    };
  6. 创建一个ConnectionCallbacks类来接收位置更新:

    GoogleApiClient.ConnectionCallbacks mConnectionCallbacks = new GoogleApiClient.ConnectionCallbacks() {
        @Override
        public void onConnected(Bundle bundle) {
            Log.i("onConnected()", "start");
            try {
                LocationServices.FusedLocationApi.requestLocationUpdates(
                    mGoogleApiClient, mLocationRequest, mLocationListener);
            } catch (SecurityException e) {
                Log.i("onConnected()","SecurityException: "+e.getMessage());
            }
        }
        @Override
        public void onConnectionSuspended(int i) {}
    };
  7. 创建一个OnConnectionFailedListener类:

    GoogleApiClient.OnConnectionFailedListener mOnConnectionFailedListener = new GoogleApiClient.OnConnectionFailedListener() {
        @Override
        public void onConnectionFailed(ConnectionResult connectionResult) {
            Toast.makeText(MainActivity.this, connectionResult.toString(), Toast.LENGTH_LONG).show();
            Log.i("onConnected()", "SecurityException: " +connectionResult.toString());
        }
    };
  8. 将以下代码添加到现有的onCreate()回调中:

    mTextView = (TextView) findViewById(R.id.textView);
    setupLocationRequest();
  9. 创建setupLocationRequest()方法:

    protected synchronized void setupLocationRequest() {
        mLocationRequest = new LocationRequest();
        mLocationRequest.setInterval(10000);
        mLocationRequest.setFastestInterval(10000);
        mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
        mGoogleApiClient = new GoogleApiClient.Builder(this)
                .addConnectionCallbacks(mConnectionCallbacks)
                .addOnConnectionFailedListener(mOnConnectionFailedListener)
                .addApi(LocationServices.API)
                .build();
        mGoogleApiClient.connect();
    }
  10. 您已经准备好在设备或模拟器上运行应用。

它是如何工作的...

这个配方是类似于如何获取最后位置的配方,因为我们需要像之前一样设置GoogleApiClient。但是,我们不是按需调用lastLocation()方法,而是通过LocationListener类调用requestLocationUpdates()方法来接收定期位置更新。

requestLocationUpdates()方法需要三个参数:

  • GoogleApiClient
  • LocationRequest
  • LocationListener

我们像以前一样创建GoogleApiClient。这是创建我们的LocationRequest的代码:

mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(10000);
mLocationRequest.setFastestInterval(10000);
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)

在调用setInterval()时,通常最好使用最慢的延迟,因为它需要更少的设备资源。调用setPriority()时也是同样的想法。第三个参数LocationListener,是我们定义回调方法onLocationChanged()的地方。这里我们只显示位置数据和位置时间戳。

还有更多...

与以前的安卓应用编程接口不同,GoogleApiClient应用编程接口不允许选择特定的传感器进行位置更新。如模拟地点部分所述,如何获得最后一个地点,使用LocationRequest.PRIORITY_HIGH_ACCURACY以及ACCESS_FINE_LOCATION的许可应该使用全球定位系统传感器。参考模拟位置部分,了解模拟位置的说明。

停止接收位置更新

当您的应用不再需要位置更新时,调用removeLocationUpdates()方法,如下所示:

LocationServices.FusedLocationApi.removeLocationUpdates(
    mGoogleApiClient, mLocationListener);

通常,当应用不再处于前台时,您会希望禁用更新,但这取决于您的特定应用要求。如果您的应用需要不断更新,创建一个后台服务来处理回调可能会更好。

另见

创建并监控地理围栏

如果您的应用需要知道用户何时进入某个位置,那么除了必须持续检查用户位置之外,还有一种选择:地理围栏。地理围栏是一个位置(纬度和经度)以及一个半径。您可以创建地理围栏,并让系统在用户进入您指定的位置附近时通知您。(安卓目前允许每个用户最多 100 个地理围栏。)

地理围栏属性包括:

  • 位置:经纬度
  • 半径:圆的大小(米)
  • 游荡延迟:用户在发送通知前可以在半径内停留多长时间
  • 到期 : 地理围栏自动到期还有多久
  • 过渡 : 这些是列举如下:
    • GEOFENCE_TRANSITION_ENTER
    • GEOFENCE_TRANSITION_EXIT
    • INITIAL_TRIGGER_DWELL

本食谱将向您展示如何创建地理围栏对象,并使用它创建GeofencingRequest的实例。

做好准备

在 Android Studio 中创建新项目,并将其称为:Geofence。使用默认的电话&平板电脑选项,当提示输入活动类型时,选择空活动

怎么做...

我们不需要这个食谱的布局,因为我们将使用祝酒词和通知进行用户交互。我们需要为IntentService创建一个额外的 Java 类,它处理地理围栏警报。打开安卓清单,按照以下步骤操作:

  1. 添加以下权限:

    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
  2. 打开文件build.gradle (Module: app)并在dependencies部分添加以下语句:

    compile 'com.google.android.gms:play-services:8.4.0'
  3. 创建一个名为GeofenceIntentService的新 Java 类,扩展IntentService类。申报如下:

    public class GeofenceIntentService extends IntentService {
  4. 添加以下构造函数:

    public GeofenceIntentService() {
        super("GeofenceIntentService");
    }
  5. 添加onHandleIntent()接收地理围栏警报:

    protected void onHandleIntent(Intent intent) {
        GeofencingEvent geofencingEvent = GeofencingEvent.fromIntent(intent);
        if (geofencingEvent.hasError()) {
            Toast.makeText(getApplicationContext(), "Geofence error code= " + geofencingEvent.getErrorCode(), Toast.LENGTH_SHORT).show();
            return;
        }
        int geofenceTransition = geofencingEvent.getGeofenceTransition();
        if (geofenceTransition == Geofence.GEOFENCE_TRANSITION_DWELL) {
            sendNotification();
        }
    }
  6. 添加sendNotification()方法向用户显示消息:

    private void sendNotification() {
        Log.i("GeofenceIntentService", "sendNotification()");
        Uri notificationSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
        NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
                .setSmallIcon(R.mipmap.ic_launcher)
                .setContentTitle("Geofence Alert")
                .setContentText("GEOFENCE_TRANSITION_DWELL")
                .setSound(notificationSoundUri)
                .setLights(Color.BLUE, 500, 500);
        NotificationManager notificationManager = (NotificationManager) getApplicationContext().getSystemService(Context.NOTIFICATION_SERVICE);
        notificationManager.notify(0, notificationBuilder.build());
    }
  7. 打开安卓清单,在<application>元素中添加以下内容,与<activity>元素处于同一级别:

    <service android:name=".GeofenceIntentService"/>
  8. 打开MainActivity.java并添加以下全局变量:

    private final int MINIMUM_RECOMENDED_RADIUS=100;
    GoogleApiClient mGoogleApiClient;
    PendingIntent mGeofencePendingIntent;
  9. 创建以下的类:

    ResultCallback mResultCallback = new ResultCallback() {
        @Override
        public void onResult(Result result) {
            Log.i("onResult()", "result: " + result.getStatus().toString());
        }
    };
  10. 创建ConnectionCallbacks类:

```java
GoogleApiClient.ConnectionCallbacks mConnectionCallbacks = new GoogleApiClient.ConnectionCallbacks() {
    @Override
    public void onConnected(Bundle bundle) {
        try {
          LocationServices.GeofencingApi.addGeofences(
              mGoogleApiClient,
              createGeofencingRequest(),
              getGeofencePendingIntent()
          ).setResultCallback(mResultCallback);
        } catch (SecurityException e) {
            Log.i("onConnected()", "SecurityException: " + e.getMessage());
        }
    }
    @Override
    public void onConnectionSuspended(int i) {}
};
```
  1. 创建一个OnConnectionFailedListener类:
```java
GoogleApiClient.OnConnectionFailedListener mOnConnectionFailedListener = new GoogleApiClient.OnConnectionFailedListener() {
    @Override
    public void onConnectionFailed(ConnectionResult connectionResult) {
        Log.i("onConnectionFailed()", "connectionResult: " +connectionResult.toString());
    }
};
```
  1. 将以下代码添加到现有的onCreate() 回调中:
```java
  setupGoogleApiClient();
```
  1. 添加设置GoogleAPIClient :
```java
protected synchronized void setupGoogleApiClient() {
    mGoogleApiClient = new GoogleApiClient.Builder(this)
        .addConnectionCallbacks(mConnectionCallbacks)
        .addOnConnectionFailedListener(mOnConnectionFailedListener)
        .addApi(LocationServices.API)
        .build();
    mGoogleApiClient.connect();
}
```

的方法
  1. 创建setupGoogleApiClient()方法:
```java
protected synchronized void setupGoogleApiClient() {
    mGoogleApiClient = new GoogleApiClient.Builder(this)
        .addConnectionCallbacks(mConnectionCallbacks)
        .addOnConnectionFailedListener(mOnConnectionFailedListener)
        .addApi(LocationServices.API)
        .build();
    mGoogleApiClient.connect();
}
```
  1. 使用以下方法创建待定意图:
```java
private PendingIntent getGeofencePendingIntent() {
    if (mGeofencePendingIntent != null) {
        return mGeofencePendingIntent;
    }
    Intent intent = new Intent(this, GeofenceIntentService.class);
    return PendingIntent.getService(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
}
```
  1. 创建geofence对象,并将其添加到请求列表中:
```java
private List createGeofenceList() {
    List<Geofence> geofenceList = new ArrayList<Geofence>();
    geofenceList.add(new Geofence.Builder()
            .setRequestId("GeofenceLocation")
            .setCircularRegion(
                    37.422006, //Latitude
                    -122.084095, //Longitude
                    MINIMUM_RECOMENDED_RADIUS)
            .setLoiteringDelay(30000)
            .setExpirationDuration(Geofence.NEVER_EXPIRE)
            .setTransitionTypes(Geofence.GEOFENCE_TRANSITION_DWELL)
    .build());
    return geofenceList;
}
```
  1. 创建 createGeofencingRequest()方法如下:
```java
private GeofencingRequest createGeofencingRequest() {
    GeofencingRequest.Builder builder = new GeofencingRequest.Builder();
    builder.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_DWELL);
    builder.addGeofences(createGeofenceList());
    return builder.build();
}
```
  1. 您已经准备好在设备或模拟器上运行应用。

它是如何工作的...

首先,我们添加ACCESS_FINE_LOCATION权限,因为这是地理围栏所必需的。我们设置GoogleApiClient就像我们在之前的食谱中所做的一样,等到onConnected()被调用来设置GeofencingApi

在调用GeofencingApi.addGeofences()方法之前,我们必须准备三个对象:

  • GoogleApiClient
  • 地理围栏请求
  • 待定意向

我们已经创造了GoogleApiClient,我们保存在mGoogleApiClient中。

要创建地理围栏请求,我们使用GeofencingRequest.Builder。构建器需要地理围栏对象的列表,这些对象是用createGeofenceList()方法创建的。(即使我们只创建了一个地理围栏对象,构建器也需要一个列表,所以我们只需将我们的单个地理围栏添加到一个ArrayList中。)这里是我们设置地理围栏属性的地方:

.setRequestId("GeofenceLocation")
.setCircularRegion(
        37.422006, //Latitude
        -122.084095, //Longitude
        MINIMUM_RECOMENDED_RADIUS)
.setLoiteringDelay(30000)
.setExpirationDuration(Geofence.NEVER_EXPIRE)
.setTransitionTypes(Geofence.GEOFENCE_TRANSITION_DWELL)

只有游荡延迟是可选的,但是我们需要它,因为我们正在使用DWELL转换。当调用setTransitionTypes()时,我们可以使用OR运算符组合多个转换类型,如管道所示。这里有一个用ENTEREXIT代替的例子:

.setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER | Geofence.GEOFENCE_TRANSITION_EXIT)

在本例中,我们使用了与模拟器相同的默认纬度和经度。根据需要更改这些值。

我们对Geofence.Builder()的调用创建了地理围栏对象。地理围栏列表准备就绪后,我们调用GeofencingRequest.Builder并将初始触发器设置为INITIAL_TRIGGER_DWELL。(如果您更改了前面的转换类型,您可能还想更改初始触发器。)

我们需要的最后一个对象是待定意图,这是当地理围栏标准满足时,系统将如何通知我们的应用。我们创建了GeofenceIntentService来通过向用户发送通知来处理地理围栏意图。(有关通知的更多信息,请参考第 7 章警报和通知中的灯光、动作和声音还原使用通知食谱。)

创建了所有三个对象,我们只需调用LocationServices.GeofencingApi.addGeofences()并等待通知到达。

还有更多...

要停止接收地理围栏通知,您可以使用RequestID参数或PendingIntent调用removeGeofences()方法。以下示例使用了我们用于通知的相同PendingIntent方法:

LocationServices.GeofencingApi.removeGeofences(
    mGoogleApiClient,
    getGeofencePendingIntent()
).setResultCallback(mResultCallback);

另见