转:Android——定位和地图

 

Location and Maps

Quickview

  • 你的应用程序可以利用Android提供的定位框架(location framework)来确定设备的位置和方向,并且能够进行更新。
  • 可以利用Google Maps外部类库来显示和管理地图数据

 开发基于地理位置的服务可以使用 android.location类和Google Maps 外部类库来开发。

Location Services

可以利用android.location包来访问设备中的定位服务。Location framework的核心组件是LocationManager系统服务,该服务提供了确定位置的APIs和内置设备的方向(应该是电子罗盘了,如果可用的话)。

要获得一个LocationManager的实例,无需直接初始化,而是通过调用 getSystemService(Context.LOCATION_SERVICE)来获取一个实例。

一旦获得一个LocationManager的实例,你就可以在程序中做如下三件事:

  • Query for the list of all LocationProviders for the last known user location.
  • 注册/解注册到一个定位提供商(specified either by criteria or name)来周期性地更新用户的当前位置。
  • Register/unregister for a given Intent to be fired if the device comes within a given proximity (specified by radius in meters) of a given lat/long.

Google Maps External Library

Google提供的地图外部类库——com.google.android.maps package. 这个包的类提供了内建的地图碎片的下载、翻译和缓存, 此外,还有很多显示选项和控制。

在这个类库中的核心类是com.google.android.maps.MapView, 是 ViewGroup的子类。一个MapView显示从Google Maps服务获得的图形和数据。当MapView获得焦点的时候,它将捕捉用户按下的键和触摸姿势来显示和放缩地图,包括管理额外的地图标题的网络请求。它还包含了供用户控制地图的必须的UI元素。你的应用程序还能够使用MapView类提供的方法来编程控制MapView,并能够在地图上绘制一些覆盖的按钮等UI元素。

Google Maps外部类库不是标准的Android库的一部分,所以它可能并不包含在一些编译好的Android设备中,也不包含在Android SDK中。但是你能够使用com.google.android.maps包中的类进行开发,Google Maps外部类库将会作为Android SDK的Google APIs插件存在。

获取更多的Google Maps外部类库的信息,以及如何下载使用Google APIs插件,可以访问:

http://code.google.com/android/add-ons/google-apis

For your convenience, the Google APIs add-on is also available as a downloadable component from the Android SDK and AVD Manager (see Adding SDK Components).

Note: In order to display Google Maps data in a MapView, you must register with the Google Maps service and obtain a Maps API Key. For information about how to get a Maps API Key, see Obtaining a Maps API Key.

Obtaining User Location

Quickview

  • 网络位置提供商提供好的位置数据而且需要GPS
  • 获取用户位置会消耗大量的电力,所以要注意你能花费多长的时间来更新位置。

Key classes

  1. LocationManager
  2. LocationListener

要了解用户哪儿需要你的应用程序更加智能以传递更好的信息给用户。 当开发一个基于位置的应用程序时,你能够利用GPS和Android的网络位置提供商来获取用户位置。尽管GPS是更加精确地,但它仅在户外使用,它也会快速地消耗大量的电量,并且不能尽快地返回位置信息。Android的网络位置提供商使用cell tower(基塔)和Wi-FI信令来确定用户的位置,不管用户在户内还是户外,提供用户的位置信息,而且速度更快,消耗电量更少。为了获取到用户位置,你的应用程序可以利用GPS和网络位置提供商,或者只是使用其中一个。

Challenges in Determining User Location

在一个移动设备上获取用户位置可能是结构复杂的。之所以读取用户位置出错或者不精确,有以下几方面的原因。

  • Multitude of location sources

    GPS, Cell-ID, and Wi-Fi can each provide a clue to users location. Determining which to use and trust is a matter of trade-offs in accuracy, speed, and battery-efficiency.

  • User movement

    Because the user location changes, you must account for movement by re-estimating user location every so often.

  • Varying accuracy

    Location estimates coming from each location source are not consistent in their accuracy. A location obtained 10 seconds ago from one source might be more accurate than the newest location from another or same source.

上述问题使得获取一个可靠的用户位置是比较困难的。这个文档提供信息帮助你解决这些问题以获取更可靠的位置信息。它也提供一些方法,这些方法在你的应用程序中可以使用,以提供给用户一个精确的和灵敏的地理位置体验。

在详细讲述上面描述的一些位置错误之前,这儿先介绍你怎样能够获取到用户的位置信息。

在Android上,是通过回调函数来获取用户的位置的。调用LocationManager的requestLocationUpdates表示请求接收位置更新,需要传递一个LocationListener给它。传递给它的LocationListener必须实现几个回调函数,然后当用户位置更新或服务状态改变的时候,Location Manager就能够调用这些方法来进行应用程序方面的处理。。

// Acquire a reference to the system Location Manager

LocationManager locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);

// Register the listener with the Location Manager to receive location updates
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, locationListener);

// Define a listener that responds to location updates
LocationListener locationListener = new LocationListener() {
public void onLocationChanged(Location location) {
// Called when a new location is found by the network location provider.
makeUseOfNewLocation(location);
}
public void onStatusChanged(String provider, int status, Bundle extras) {}
public void onProviderEnabled(String provider) {}
public void onProviderDisabled(String provider) {}
}
   requestLocationUpdates()方法的第一个参数是位置提供者的类型(在这种情况中,使用的是基于基塔和Wi-Fi的网路位置提供商)。

 

 你能够使用第二个和第三个参数来控制你的listener接收更新的频率—第二个参数是notifications之间的最小时间间隔,第三个是notifications之间的最小变化距离—两个都设置为0表示以最快的频率更新。最后一个参数是你的LocationListener。

如果想要由GPS提供位置更新,那么把NETWORK_PROVIDER更换为GPS_PROVIDER。如果调用requestLocationUpdates()两次,一次使用NETWORK_PROVIDER,一次使用GPS_PROVIDER,那么你就可以从网络位置提供商和GPS获取用户当前位置。

Requesting User Permissions

为了能够从NETWORK_PROVIDER或者GPS_PROVIDER接收位置更新,你必须通过声明ACCESS_COARSE_LOCATION或者ACCESS_FINE_LOCATION权限来请求用户权限。这些都是在你的Android manifest文件中设置的。例如:

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

没有这些权限,你的应用程序在运行的时候是无法获取到位置更新的。

 

 

Note:

如果你使用NETWORK_PROVIDER和GPS_PROVIDER,那么请使用ACCESS_FINE_LOCATION权限;

如果你只使用NETWORK_PROVIDER,那么使用ACCESS_COARSE_LOCATION权限。

Defining a Model for the Best Performance

基于位置的应用程序现在是非常普通的,但为了处理较差的精确度、用户移动,以及使用多种方法获取位置信息,还要节约电量,所以获取用户位置是非常复杂的。在节约电量的同时,穿越障碍物而获取到一个适合的用户位置,你必须定义一个一致的模型,这个模型定义了你的应用程序怎样获取到用户的位置信息。这个模型包含了,你什么时候开始或者停止监测用户位置更新和什么时候使用缓存存储位置数据。

Flow for obtaining user location

下面是获取用户位置的一个典型的处理流程:

  1. 启动程序。
  2. 之后,开始监听从指定的位置提供商获取用户位置更新。
  3. 通过过滤,小精度修复,以位置一个当前估计最好的位置信息。
  4. 停止接收位置更新。
  5. 利用最后估计的较好的位置信息。

图1在一个时间轴上显示了这个过程。它展示了应用程序接收位置更新的时间以及该时刻发生的时间。

 转:Android——定位和地图_第1张图片

由此可见,在你的应用程序中需要多次做决策来提供用户位置获取的服务。

 

Deciding when to start listening for updates

你可能在你的程序启动之后就尽快的开始监听位置更新信息,或者在用户激活某个特性之后。但要知道,监听用户位置修复的过程可能会消耗大量的电力,但短的时间又不能获取到足够精度的位置信息。

就像上面所展示的,你可以在调用requestLocationUpdates()之后就开始监听位置更新。

LocationProvider locationProvider = LocationManager.NETWORK_PROVIDER;
// Or, use GPS location data:
// LocationProvider locationProvider = LocationManager.GPS_PROVIDER;
locationManager.requestLocationUpdates(locationProvider, 0, 0, locationListener);
 

Getting a fast fix with the last known location

你的location listener接收第一次位置修复所花的时间通常是非常长的。如果你的location listener接收到一个更加精确的位置,你应该调用getLastKnownLocation(String)来获取一个缓存的位置。

LocationProvider locationProvider = LocationManager.NETWORK_PROVIDER;
// Or use LocationManager.GPS_PROVIDER
Location lastKnownLocation = locationManager.getLastKnownLocation(locationProvider);
 

Deciding when to stop listening for updates

你的程序中,判断什么时候不需要新的修复的逻辑可以是非常简单,也可以是非常复杂的。开始获得位置信息和开始使用位置信息之间的短暂的时间间隔,有助于位置估计的精度。 因为长时间监测位置消耗大量的电力,所以你一旦获得你所需的位置信息,就应该调用removeUpdates(PendingIntent)来停止监听。

 

// Remove the listener you previously added
locationManager.removeUpdates(locationListener);
 

Maintaining a current best estimate

你可能希望最近的位置修复是最精确的。 However, because the accuracy of a location fix varies, the most recent fix is not always the best. You should include logic for choosing location fixes based on several criteria. The criteria also varies depending on the use-cases of the application and field testing.

Here are a few steps you can take to validate the accuracy of a location fix:

  • Check if the location retrieved is significantly newer than the previous estimate.
  • Check if the accuracy claimed by the location is better or worse than the previous estimate.
  • Check which provider the new location is from and determine if you trust it more.

An elaborate example of this logic can look something like this:

private static final int TWO_MINUTES = 1000 * 60 * 2;

/** Determines whether one Location reading is better than the current Location fix
  * @param location  The new Location that you want to evaluate
  * @param currentBestLocation  The current Location fix, to which you want to compare the new one
  */
protected boolean isBetterLocation(Location location, Location currentBestLocation) {
    if (currentBestLocation == null) {
        // A new location is always better than no location
        return true;
    }

    // Check whether the new location fix is newer or older
    long timeDelta = location.getTime() - currentBestLocation.getTime();
    boolean isSignificantlyNewer = timeDelta > TWO_MINUTES;
    boolean isSignificantlyOlder = timeDelta < -TWO_MINUTES;
    boolean isNewer = timeDelta > 0;

    // If it's been more than two minutes since the current location, use the new location
    // because the user has likely moved
    if (isSignificantlyNewer) {
        return true;
    // If the new location is more than two minutes older, it must be worse
    } else if (isSignificantlyOlder) {
        return false;
    }

    // Check whether the new location fix is more or less accurate
    int accuracyDelta = (int) (location.getAccuracy() - currentBestLocation.getAccuracy());
    boolean isLessAccurate = accuracyDelta > 0;
    boolean isMoreAccurate = accuracyDelta < 0;
    boolean isSignificantlyLessAccurate = accuracyDelta > 200;

    // Check if the old and new location are from the same provider
    boolean isFromSameProvider = isSameProvider(location.getProvider(),
            currentBestLocation.getProvider());

    // Determine location quality using a combination of timeliness and accuracy
    if (isMoreAccurate) {
        return true;
    } else if (isNewer && !isLessAccurate) {
        return true;
    } else if (isNewer && !isSignificantlyLessAccurate && isFromSameProvider) {
        return true;
    }
    return false;
}

/** Checks whether two providers are the same */
private boolean isSameProvider(String provider1, String provider2) {
    if (provider1 == null) {
      return provider2 == null;
    }
    return provider1.equals(provider2);
}
 

Adjusting the model to save battery and data exchange

As you test your application, you might find that your model for providing good location and good performance needs some adjustment. Here are some things you might change to find a good balance between the two.

Reduce the size of the window

A smaller window in which you listen for location updates means less interaction with GPS and network location services, thus, preserving battery life. But it also allows for fewer locations from which to choose a best estimate.

Set the location providers to return updates less frequently

Reducing the rate at which new updates appear during the window can also improve battery efficiency, but at the cost of accuracy. The value of the trade-off depends on how your application is used. You can reduce the rate of updates by increasing the parameters in requestLocationUpdates() that specify the interval time and minimum distance change.

Restrict a set of providers

Depending on the environment where your application is used or the desired level of accuracy, you might choose to use only the Network Location Provider or only GPS, instead of both. Interacting with only one of the services reduces battery usage at a potential cost of accuracy.

Common application cases

There are many reasons you might want to obtain the user location in your application. Below are a couple scenarios in which you can use the user location to enrich your application. Each scenario also describes good practices for when you should start and stop listening for the location, in order to get a good reading and help preserve battery life.

Tagging user-created content with a location

You might be creating an application where user-created content is tagged with a location. Think of users sharing their local experiences, posting a review for a restaurant, or recording some content that can be augmented with their current location. A model of how this interaction might happen, with respect to the location services, is visualized in figure 2.

你可能感兴趣的:(android)