使融合定位提供程序LocationClient更易于使用

10
假设我的应用中有5个不同的活动,希望使用LocationClient.getLastLocation()来获取上次已知的位置。这似乎很简单。
理想情况下,我只需在每个活动中创建一个LocationClient并调用getLastLocation()。但是,还需要进行一些额外的工作来连接到Google Play服务,例如调用LocationClient.connect()并处理onConnectedonDisconnectedonConnectionFailed回调。文档在此处:https://developer.android.com/training/location/retrieve-current.html 据我所知,我五个不同的活动都必须处理LocationClient的生命周期方法。它们也不能立即在onCreate()中调用getLastLocation(),因为该活动的连接可能尚未建立。
是否有一种简单的方法来简化LocationClient的生命周期,以便在我为应用程序建立连接后,任何新活动中都可以立即使用getLastLocation()

你已经找到这个问题的解决方案了吗? - Franziskus Karsunke
4个回答

5
我使用了融合位置提供者API来获取定期的位置更新。我将其实现在后台服务中(例如,LocationUpdateService extends Service)。以前我使用的是Android位置框架API,但它对电池使用不好。融合位置提供者API是为了实现高效的电池使用而最佳的方法。
我还准备了一些步骤的笔记,这些步骤是必要的(连同其他有用的信息)。简单地说,这是目前在Android平台上获取位置数据的最佳方法。Google Play服务提供了许多位置API来获取位置数据(例如用户的当前位置或您可以说设备的最后已知位置)。
融合位置提供者是Google Play服务中的位置API之一。 以下是先决条件:
  1. 已将Google Play服务SDK用作库项目(并且Google Play服务已正确安装在您的设备上)。

    • 从SDK管理器下载并安装Google Play服务组件,并将该库添加到您的项目中。
    • 从android google-play-services_lib中导入GooglePlayServices库到您的开发项目中作为Library project。
  2. 应具有实际设备,因为此API不能在模拟器中工作。

融合位置提供者能够智能地管理底层位置技术(GPS/Wi-Fi/网络提供商连接),并根据我们的需求为我们提供最佳位置。

为什么使用它

我们可以选择一个位置提供者(网络或GPS)并请求位置更新或设置邻近警报。但是这种方法存在两个主要问题: 1. 如果我们需要定义精确位置,就必须在网络和GPS位置提供程序之间进行切换(因为GPS在室内无法工作)。 2. 邻近警报用于通知用户与位置的临近程度,这会对电池寿命造成影响。

好处

  1. 简单的API:它让我们指定高级需求,例如“高精度”或“低功率”,而不必担心位置提供者。
  2. 节省电池电量:它最小化应用程序的能量使用。基于所有传入的位置请求和可用的传感器,融合位置提供者选择最有效的方式来满足这些需求。
使用此API的步骤:
  1. Declare the location related permission in the manifest file.

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

    Or

    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
    
  2. Implement related interfaces and callbacks. Before we request location updates, we must first implement the interfaces that Location Services uses to communicate connection status to our app:

    • com.google.android.gms.common.GooglePlayServicesClient.ConnectionCallbacks: Specifies methods that Location Services calls when a location client is connected or disconnected.
    • com.google.android.gms.common.GooglePlayServicesClient.OnConnectionFailedListener
  3. Connect to Google Play Services, connecting LocationClient to the Google API. To do this, create a LocationClient object (instance of GoogleApiClient) as:

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

    And then call mLocationClient.connect();.

  4. Create an instance of FusedLocationProviderApi by using the LocationServices class as:

    private FusedLocationProviderApi fusedLocationProviderApi = LocationServices.FusedLocationApi;
    
  5. Retrieve the current location inside onConnected(Bundle bundle):

    Location currentLocation = fusedLocationProviderApi                                  .getLastLocation(mLocationClient);
    if (mCurrentLocation != null) {
        Log.d(TAG, "last location = " + mCurrentLocation.getLatitude() +
            " - " + mCurrentLocation.getLongitude());
    }           
    
  6. Create and setup a LocationRequest object:

    mLocationRequest = new LocationRequest();
    
    private void setLocationParameter() {
        // Set the update interval
        mLocationRequest.setInterval(Constants.SECONDS_TO_UP);
        // Use high accuracy
        mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
        // Set the interval ceiling to one minute
        mLocationRequest.setFastestInterval(Constants.SECONDS_TO_UP);
        // Set the distance to 10 meters.
        mLocationRequest.setSmallestDisplacement(Constants.METERS_TO_UP);
    }
    
  7. To get periodic location updates from Location Services, we send a request using a location client.

    LocationListener listener =  new LocationListener() {
        @Override
        public void onLocationChanged(Location location) {    
            Utils.locationUpdates = Utils.locationUpdates + 1;
            if (Utils.locationUpdates == 1) {
                mLocationRequest .setPriority(LocationRequest.PRIORITY_LOW_POWER);
                LocationServices.FusedLocationApi.requestLocationUpdates(mLocationClient, mLocationRequest, listener);
            }
        }
    };
    

这并没有回答如何更智能地管理不同活动中的LocationServices的问题。 - eskalera

2

1
如果您熟悉响应式编程,您必须尝试RxLocation库,它将Fused API包装成RX方式。
示例:
// Create one instance and share it
RxLocation rxLocation = new RxLocation(context);

LocationRequest locationRequest = LocationRequest.create()
                .setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
                .setInterval(5000);

rxLocation.location().updates(locationRequest)
        .flatMap(location -> rxLocation.geocoding().fromLocation(location).toObservable())
        .subscribe(address -> {
            /* do something */
        });

1

1
无法解决在onCreate()中立即调用getLastLocation()的问题。每个活动仍然必须等待onConnected回调,然后才能使用getLastLocation()。 - emmby
@emmby 你必须以某种方式管理生命周期... 你考虑过在单个活动中使用片段吗?根据每个活动中的操作,这可能行不通,但如果可以的话,这将允许你管理所有子片段的生命周期。 - Ryan S

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接