65.9K
CodeProject 正在变化。 阅读更多。
Home

反向地理编码变得简单:使用 TomTom Android SDK 获取位置详细信息

emptyStarIconemptyStarIconemptyStarIconemptyStarIconemptyStarIcon

0/5 (0投票)

2019年1月29日

CPOL
viewsIcon

8899

在本文中,我们将探讨新的 TomTom SDK 中提供的功能。

对于计算机来说,地理编码(即 GPS 坐标)非常有用,可以轻松计算出它们的精确位置。但是,对于普通人来说,处理地理编码非常困难,因为人类不会以地理编码的方式思考或谈论位置。相反,我们使用街道名称、地址和地标来确定事物的位置。

这就是为什么反向地理编码是一项如此重要的功能,它能够弥合计算机和人类之间的鸿沟。反向地理编码允许应用程序将地理编码转换为街道名称或其他人类可读的位置信息。因此,反向地理编码使得在应用程序中使用 GPS 和地理编码的精度来跟踪位置成为可能,同时仍然以人类易于理解的方式向用户呈现信息。

然而,反向地理编码的棘手之处在于,传统上并没有简单的方法可以在应用程序中利用它。不像 IP 地址那样,你可以通过 DNS 服务轻松地将其转换为域名,反向地理编码没有一种标准化的服务可以将地理编码转换为人类可读的位置信息。

幸运的是,TomTom 通过将其反向地理编码功能添加到其 SDK 中,极大地简化了开发人员在这方面的开发。该功能通过简单的 API 调用,可以非常容易地在应用程序中实现反向地理编码。

为了让大家了解反向地理编码的工作原理以及开发人员如何借助 TomTom SDK 轻松利用它,本文将介绍一个涉及在 Android 移动应用中显示位置数据的场景。我们将首先讨论使用 SDK 所需的准备工作;然后,我们将创建应用程序来确定设备的位置,使用 TomTom SDK 获取有关该位置的更多信息,最后在屏幕上显示结果。

在本文中,我们将探讨新的 TomTom SDK 中提供的功能。本文中我们将构建的示例使用了 TomTom Android SDK。Web 和 iOS SDK 也提供了相同的功能。您也可以直接从您的应用程序中使用 TomTom API。您可以通过以下链接了解 iOS 和 Web SDK。

TomTom SDK

您可以在 TomTom 开发者门户 找到开始使用 TomTom API 所需的一切。您首先需要做的是在该门户创建一个账户。在主页上,输入您的电子邮件地址,然后点击“获取免费 API 密钥”按钮。

图 1 TomTom 开发者门户

下一步是选择一个用户名并阅读服务条款。您的免费账户每天支持最多 2,500 次免费交易。如果每天 2,500 次 API 交易不够,您可以通过访问开发者仪表板中的“我的积分”屏幕来购买更多交易。

一封电子邮件将包含一个设置您账户密码的链接,然后您就可以开始了。在请求 API 密钥之前,您需要配置一个应用程序。从您的仪表板中,点击“+ 添加应用”按钮。

应用程序需要一个名称,并且您需要启用该应用程序需要访问的产品。在本示例中,我们将使用的产品是搜索 API 产品。如果您正在跟随操作,请选择搜索 API 产品,然后点击创建应用

图 2 创建新应用程序

通过访问 TomTom 开发者门户 并输入您的电子邮件地址以获取“免费 API 密钥”,您可以获得一个唯一的 API 密钥。您需要阅读并同意服务条款,并选择一个用户名。一封电子邮件会提示您设置密码,然后您就可以导航到您的仪表板并创建一个新应用程序。

应用程序将快速获得批准并在您的仪表板上显示。该条目显示了消费者 API 密钥和有关您的应用程序的信息,包括应用程序的批准状态以及它使用的每种产品。

图 3 应用程序详情,包括 API 密钥

在将 TomTom SDK 添加到我们的项目并使用它来获取我们位置的详细信息以完成我们的应用程序时,我们将需要此 API。

设置我们的项目

我使用 Android Studio 创建了这个项目,并从一个空白活动屏幕开始。打开 activity_main.xml,我添加了一个按钮 (btnGetInformation) 来触发信息请求,然后在下面添加了一组文本字段来显示有关位置的信息。我们将包含以下字段:

  • 街道地址 - txtStreet
  • 城市 - txtCity
  • 邮政编码 - txtZipCode
  • 州 - txtState

图 4 应用程序布局

现在让我们打开 MainActivity.java,连接到这些控件中的每一个,然后我们可以为按钮添加一个 EventListener,并连接到设备的 Location Manager。

public class MainActivity extends AppCompatActivity {

    private Button btnInformation;
    private TextView txtStreet;
    private TextView txtCity;
    private TextView txtState;
    private TextView txtZipCode;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        btnInformation = findViewById(R.id.btnGetInformation);
        txtStreet = findViewById(R.id.txtStreet);
        txtCity = findViewById(R.id.txtCity);
        txtZipCode = findViewById(R.id.txtZipCode);
        txtState = findViewById(R.id.txtState);
    }
}
图 5 主活动 (MainActivity.java) 的控件初始化

从设备捕获位置信息

我们将设置我们的应用程序以从设备上的 GPS 位置服务获取位置更新。在此之前,我们需要在 AndroidManifest.xml 文件中添加一个 uses-permission 条目。

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
图 6 为位置服务添加权限

接下来,我们将向 MainActivity.java 文件添加一个 LocationManager 和一个 LocationListener

private LocationManager locationManager;
private LocationListener locationListener;

现在,我们将在 onCreate 方法中初始化它们。LocationListener 有四个需要我们实现的方法。我们将在项目的稍后阶段实现 onLocationChanged 方法。

locationManager = (LocationManager) this.getSystemService(LOCATION_SERVICE);
locationListener = new LocationListener() {
    @Override
    public void onLocationChanged(Location location) {
    }

    @Override
    public void onStatusChanged(String provider, int status, Bundle extras){
    }

    @Override
    public void onProviderEnabled(String provider) {
    }

    @Override
    public void onProviderDisabled(String provider) {
    }
};
图 7 LocationManager 和 LocationListener 的实现

现在我们需要启用 LocationManager 并确保用户已授予我们访问位置服务的权限。我们将在 onCreate 方法中检查权限,并且我们也将把检查添加到重写的 onRequestPermissionResult 方法中。我们用来开始接收更新的命令是:

locationManager.requestLocationUpdates(
    LocationManager.GPS_PROVIDER, 
    5000, 
    1,  
    locationListener
);

参数指定

  • 位置的来源(在本例中为 GPS 提供者)
  • 更新之间的最短时间(我们选择了 5000 毫秒或 5 秒)
  • 更新之间的最短距离(我们选择了 1 米)
  • LocationListener 对象。

我们将在 onCreate 中检查权限

if (ActivityCompat.checkSelfPermission(
    this,
    Manifest.permission.ACCESS_FINE_LOCATION
    ) != PackageManager.PERMISSION_GRANTED
         && ActivityCompat.checkSelfPermission(
             this,
             Manifest.permission.ACCESS_COARSE_LOCATION
         ) != PackageManager.PERMISSION_GRANTED) {
             ActivityCompat.requestPermissions(
                 this,
                 new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
                 1
             );
} else {
    locationManager.requestLocationUpdates(
        LocationManager.GPS_PROVIDER, 
        5000, 
        1, 
        locationListener
    );
}
图 8 在 onCreate 方法中检查权限

我们还将把权限检查添加到 onRequestPermissionsResult 方法中。

@Override
public void onRequestPermissionsResult(
    int requestCode, 
    @NonNull String[] permissions, 
    @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(
            requestCode, 
            permissions, 
            grantResults
        );

        if (grantResults.length > 0 
            && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            if (ContextCompat.checkSelfPermission(
                this, 
                Manifest.permission.ACCESS_FINE_LOCATION) ==             
                PackageManager.PERMISSION_GRANTED) {                      
                    locationManager.requestLocationUpdates(
                         LocationManager.GPS_PROVIDER, 
                         5000, 
                         1, 
                         locationListener
                    ); 
                }
        }
}
图 9 在 onRequestPermissionsResult 方法中检查权限

因此,现在无论我们的用户是已经授予了应用程序使用设备位置的权限,还是在打开应用程序时授予权限,应用程序现在都可以访问该位置。在继续之前,我们再添加一项。我们将初始化一个名为 currentLocation、类型为 Location 的变量,并将在 LocationListeneronLocationChanged 方法中设置它。

private Location currentLocation;

每当位置服务广播更改时,我们都会设置 currentLocation。

@Override
public void onLocationChanged(Location location) {
    currentLocation = location;
}
图 10 在 LocationListener 中设置 currentLocation 属性

让我们添加 TomTom SDK,以便我们可以获取当前位置并请求有关它的更多信息来完成我们的应用程序。

添加 TomTom 支持

我们需要将 TomTom SDK 添加为我们项目的依赖项。第一步是将 TomTom 存储库添加到我们的 build.gradle 文件中。我们需要项目对应的 Gradle 构建文件,并在文件中找到 allprojects 对象。将 TomTom 存储库添加到该对象。

allprojects {
    repositories {
        google()
        jcenter()
        maven {
            url "https://maven.tomtom.com:8443/nexus/content/repositories/releases/"
        }
    }
}
图 11 添加 TomTom 存储库

现在我们可以访问存储库了,打开应用程序的 Gradle 构建文件,并将以下依赖项添加到 dependencies 对象中。

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'com.android.support:appcompat-v7:28.0.0'
    implementation 'com.android.support.constraint:constraint-layout:1.1.3'
    implementation 'com.tomtom.online:sdk-search:2.+'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'com.android.support.test:runner:1.0.2'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
}
图 12 添加 TomTom Search SDK

您可能需要先刷新项目的 Gradle 库,但这些更改会将 TomTom 搜索功能添加到您的项目中。最后一步是使用我们通过 TomTom 开发者门户 创建的 API 密钥来授权 API 访问。

打开 AndroidManifest.xml 文件,并在最后一个 activity 对象之后、application 对象关闭之前,添加以下 meta-data 对象。请确保将 ReplaceWithAPIKey 替换为您的 API 密钥。

<meta-data
    android:name="OnlineSearch.Key"
    android:value="ReplaceWithAPIKey" />
图 13 为 TomTom Search SDK 添加 API 密钥

对位置进行反向地理编码

我们要做的第一件事是实现几个方法来配置 API 并允许构建查询。将以下函数添加到 MainActivity.java 文件中。我们将传递应用程序上下文,这是 API 使用我们的 API 密钥进行配置的方式。

protected SearchApi createSearchAPI() {
    SearchApi searchApi = OnlineSearchApi.create(getApplicationContext());
    return searchApi;
}
图 14 初始化 SearchAPI 的函数

下一个函数为我们构造一个搜索查询。我们接受纬度和经度值并返回一个查询对象。

protected ReverseGeocoderSearchQuery createReverseGeocoderQuery(
    double latitude, 
    double longitude) {
        return ReverseGeocoderSearchQueryBuilder
                .create(latitude, longitude)
                .build();
}
图 15 构建我们的 ReverseGeocoderQuery 对象的函数

最后,让我们构建我们的 reverseGeocode 函数,该函数配置与 API 的连接,构建查询,然后处理结果。

protected void reverseGeocode(
    final double latitude, 
    final double longitude) {
        SearchApi searchAPI = createSearchAPI();
        ReverseGeocoderSearchQuery reverseGeocoderQuery =
            createReverseGeocoderQuery(latitude, longitude);
        searchAPI.reverseGeocoding(
            reverseGeocoderQuery, new RevGeoSearchResultListener() {
                @Override
                public void onSearchResult(ReverseGeocoderSearchResponse   response) {
                    List<ReverseGeocoderFullAddress> addresses =   
                        response.getAddresses();
                    if (addresses.size() > 0) {
                        Address address = addresses.get(0).getAddress();
                        txtStreet.setText(address.getStreetNumber() + ' ' + address.getStreetName());
                        txtCity.setText(address.getMunicipality());
                        txtState.setText(address.getCountrySubdivision());
                        txtZipCode.setText(address.getPostalCode());
                    }
                }

                @Override
                public void onSearchError(SearchError error) {
                    Log.d("Address: ",  getApplicationContext().getString(R.string.reverse_geocoding_error));
                }
        });
}
图 15 构建我们的 ReverseGeocoderQuery 对象的函数

我们需要做的最后一件事是将按钮连接到使用 currentLocation 运行 reverseGeocode 函数。将以下内容添加到 onCreate 函数的末尾。

btnGetInformation.setOnClickListener(v ->
    reverseGeocode(currentLocation.getLatitude(),
                   currentLocation.getLongitude()));
图 16 为按钮添加点击监听器

运行应用程序

您可以在模拟器中运行您的应用程序,或将其安装在 Android 设备上。我用运行 Android API 28 版本的 Pixel 2 模拟器测试了我的应用程序。我将坐标修改为 45.512046, -122.627833,然后点击了获取位置信息按钮。

图 17 完成的应用演示

附加信息

如果您想了解更多关于 TomTom API 中可用选项的信息,您可以访问在线文档或使用 API 资源管理器来尝试不同的参数并查看它们是如何协同工作的。

如果您想下载此示例的代码,可以在此处找到。您需要在 AndroidManifest 文件中添加您的 API 密钥才能运行该应用程序。

© . All rights reserved.