当前位置: 首页 > 工具软件 > Geocoder > 使用案例 >

geocoder_Android Geocoder反向地理编码

隗和裕
2023-12-01

geocoder

Android Geocoder class is used for reverse geocoding i.e. retrieving the address from the location on the Google Map.
If you aren’t aware of how to use Google Maps in your Android Application, refer android google maps tutorial before moving ahead.

Android Geocoder类用于反向地理编码,即从Google Map上的位置检索地址。
如果您不知道如何在Android应用程序中使用Google Maps,请先阅读android Google Maps教程,然后再继续。

Android Geocoder (Android Geocoder)

Android Geocoder class is used for Geocoding as well as Reverse Geocoding. Geocoding refers to transforming street address or any address into latitude and longitude. Reverse Geocoding refers to transforming latitude and longitude into its corresponding street address.

Android Geocoder类用于地理编码以及反向地理编码。 地理编码是指将街道地址或任何地址转换为纬度和经度。 反向地理编码是指将纬度和经度转换为其对应的街道地址。

Address class helps in fetching the street address, locality, sub-locality, city, country, landmark etc. features of the location.

Address类别有助于获取街道地址,位置,子位置,城市,国家/地区地标等特征。

Using the above two classes we’ll be fetching the current marker address on the Google Maps in our application. Let’s start with the android reverse geocoding example project.

使用以上两个类,我们将在应用程序中的Google Maps上获取当前标记地址。 让我们从android反向地理编码示例项目开始。

Android Geocoder反向地理编码项目结构 (Android Geocoder Reverse Geocoding Project Structure)

We’ll need the google maps and google places api. So let’s add them in the build.gradle file as shown below.

我们需要Google MapsGoogle Places API。 因此,如下所示,将它们添加到build.gradle文件中。

apply plugin: 'com.android.application'


allprojects {
    repositories {
        jcenter()
        maven {
            url "https://maven.google.com"
        }
    }
}



android {
    compileSdkVersion 26
    buildToolsVersion "26.0.1"
    defaultConfig {
        applicationId "com.journaldev.reversegeocoding"
        minSdkVersion 16
        targetSdkVersion 26
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
        exclude group: 'com.android.support', module: 'support-annotations'
    })
    compile 'com.android.support:appcompat-v7:26.0.1'
    compile 'com.android.support:cardview-v7:26.0.1'
    compile 'com.android.support.constraint:constraint-layout:1.0.2'
    compile 'com.google.android.gms:play-services-maps:11.0.4'
    compile 'com.google.android.gms:play-services-places:11.0.4'
    testCompile 'junit:junit:4.12'
}

Get the relevant API key from the Google Developer Console and add it inside the meta-data in the AndroidManifest.xml file. If you aren’t aware of integrating Google APIs in your application, refer this tutorial before moving ahead.

从Google Developer Console获取相关的API密钥,并将其添加到AndroidManifest.xml文件的元数据中。 如果您不知道将Google API集成到应用程序中,请先阅读教程,然后再继续。

Android反向地理编码代码 (Android Reverse Geocoding Code)

The code for the activity_main.xml layout is given below.

下面给出了activity_main.xml布局的代码。

<RelativeLayout xmlns:android="https://schemas.android.com/apk/res/android"
    xmlns:card_view="https://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.v7.widget.CardView
        android:id="@+id/cardView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="12dp"
        card_view:cardCornerRadius="0dp"
        card_view:cardElevation="0dp">

        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_gravity="center">

            <TextView
                android:id="@+id/txtLocationAddress"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentTop="true"
                android:layout_centerHorizontal="true"
                android:ellipsize="marquee"
                android:focusable="true"
                android:focusableInTouchMode="true"
                android:gravity="center"
                android:marqueeRepeatLimit="marquee_forever"
                android:maxLines="1"
                android:padding="16dp"
                android:scrollHorizontally="true"
                android:text="Current Marker Address" />

        </RelativeLayout>

    </android.support.v7.widget.CardView>


    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <fragment
            android:id="@+id/mapFragment"
            android:name="com.google.android.gms.maps.SupportMapFragment"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:tag="tag_map_fragment" />

        <FrameLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center">

            <ImageView
                android:id="@+id/centerMarker"
                android:layout_width="48dp"
                android:layout_height="48dp"
                android:layout_gravity="center"
                android:src="@drawable/black_marker" />

        </FrameLayout>

    </FrameLayout>

</RelativeLayout>

Our layout contains a CardView, which holds a TextView that’ll eventually display the current address.
The marker is placed in an ImageView at the center of the screen.

我们的布局包含一个CardView ,其中包含一个TextView,最终将显示当前地址。
标记放置在屏幕中央的ImageView中。

The code for the MainActivity.java class is given below.

下面给出MainActivity.java类的代码。

package com.journaldev.reversegeocoding;

import android.content.Intent;
import android.location.Address;
import android.location.Geocoder;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.CardView;
import android.text.TextUtils;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;

import com.google.android.gms.common.GooglePlayServicesNotAvailableException;
import com.google.android.gms.common.GooglePlayServicesRepairableException;
import com.google.android.gms.location.places.Place;
import com.google.android.gms.location.places.ui.PlaceAutocomplete;
import com.google.android.gms.maps.CameraUpdate;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.OnMapReadyCallback;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.LatLng;

import java.io.IOException;
import java.util.List;
import java.util.Locale;


public class MainActivity extends AppCompatActivity {


    TextView txtLocationAddress;
    SupportMapFragment mapFragment;
    GoogleMap map;
    LatLng center;
    CardView cardView;
    private static final int PLACE_AUTOCOMPLETE_REQUEST_CODE = 1;

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

        txtLocationAddress = findViewById(R.id.txtLocationAddress);
        txtLocationAddress.setEllipsize(TextUtils.TruncateAt.MARQUEE);
        txtLocationAddress.setSingleLine(true);
        txtLocationAddress.setMarqueeRepeatLimit(-1);
        txtLocationAddress.setSelected(true);

        cardView = findViewById(R.id.cardView);

        cardView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                try {
                    Intent intent =
                            new PlaceAutocomplete.IntentBuilder(PlaceAutocomplete.MODE_FULLSCREEN)
                                    .build(MainActivity.this);
                    startActivityForResult(intent, PLACE_AUTOCOMPLETE_REQUEST_CODE);
                } catch (GooglePlayServicesRepairableException e) {
                    printToast("Google Play Service Repair");
                } catch (GooglePlayServicesNotAvailableException e) {
                    printToast("Google Play Service Not Available");
                }
            }
        });

        mapFragment = (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.mapFragment);
        mapFragment.getMapAsync(new OnMapReadyCallback() {
            @Override
            public void onMapReady(GoogleMap googleMap) {
                map = googleMap;
                map.getUiSettings().setZoomControlsEnabled(true);
                LatLng latLng = new LatLng(20.5937, 78.9629);
                map.moveCamera(CameraUpdateFactory.newLatLngZoom(latLng, 16));
                initCameraIdle();
            }
        });
    }

    private void initCameraIdle() {
        map.setOnCameraIdleListener(new GoogleMap.OnCameraIdleListener() {
            @Override
            public void onCameraIdle() {
                center = map.getCameraPosition().target;
                getAddressFromLocation(center.latitude, center.longitude);
            }
        });
    }

    private void getAddressFromLocation(double latitude, double longitude) {

        Geocoder geocoder = new Geocoder(this, Locale.ENGLISH);


        try {
            List<Address> addresses = geocoder.getFromLocation(latitude, longitude, 1);

            if (addresses.size() > 0) {
                Address fetchedAddress = addresses.get(0);
                StringBuilder strAddress = new StringBuilder();
                for (int i = 0; i < fetchedAddress.getMaxAddressLineIndex(); i++) {
                    strAddress.append(fetchedAddress.getAddressLine(i)).append(" ");
                }

                txtLocationAddress.setText(strAddress.toString());

            } else {
                txtLocationAddress.setText("Searching Current Address");
            }

        } catch (IOException e) {
            e.printStackTrace();
            printToast("Could not get address..!");
        }
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (requestCode == PLACE_AUTOCOMPLETE_REQUEST_CODE) {
            if (resultCode == RESULT_OK) {
                Place place = PlaceAutocomplete.getPlace(this, data);
                if (!place.getAddress().toString().contains(place.getName())) {
                    txtLocationAddress.setText(place.getName() + ", " + place.getAddress());
                } else {
                    txtLocationAddress.setText(place.getAddress());
                }

                CameraUpdate cameraUpdate = CameraUpdateFactory.newLatLngZoom(place.getLatLng(), 16);
                map.animateCamera(cameraUpdate);


            } else if (resultCode == PlaceAutocomplete.RESULT_ERROR) {
                printToast("Error in retrieving place info");

            }
        }
    }

    private void printToast(String message) {
        Toast.makeText(getApplicationContext(), message, Toast.LENGTH_SHORT).show();
    }
}

Let’s break down the above code and see what it does.

让我们分解上面的代码,看看它能做什么。

  1. We’ve set the attributes setEllipize() and set setMarqueeRepeatLimit() on the TextView programmatically since setting the same attributes in xml doesn’t scroll the text on all devices anymore. The above methods make the content of TextView scroll horizontally IF the content length is greater than the TextView width.

    我们已通过编程方式在TextView上设置了属性setEllipize()setMarqueeRepeatLimit() ,因为在xml中设置相同的属性不会再在所有设备上滚动文本。 如果内容长度大于TextView的宽度,则上述方法可使TextView的内容水平滚动。
  2. Passing -1 in setMarqueeRepeatLimit() makes it scroll forever.

    setMarqueeRepeatLimit()传递-1将使其永远滚动。
  3. The Google Map is displayed using the SupportMapFragment. getMapAsync() callback is assigned to the fragment. This callback gets triggered when the Google Play Services exists.

    使用SupportMapFragment显示Google Map。 getMapAsync()回调分配给该片段。 存在Google Play服务时会触发此回调。
  4. The onMapReady() method is the one that displays the Google Map and returns a non-null instance of the GoogleMap class. We assign it to our instance variable map.
    map.getUiSettings().setZoomControlsEnabled(true) is used to set the zoom controls on the screen.

    onMapReady()方法是显示Google Map并返回GoogleMap类的非null实例的方法。 我们将其分配给实例变量map
    map.getUiSettings().setZoomControlsEnabled(true)用于在屏幕上设置缩放控件。
  5. map.moveCamera(CameraUpdateFactory.newLatLngZoom(latLng, 16)) moves the map to the location specified in the latLng(Some location in India!). The camera zooms to the location in the center of the screen where the marker is placed.

    map.moveCamera(CameraUpdateFactory.newLatLngZoom(latLng, 16))将地图移动到latLng指定的位置(印度的某些位置!)。 相机将缩放到屏幕中心放置标记的位置。
  6. setOnCameraIdleListener would listen for the movements/dragging on the map. When the movement ends the method onCameraIdle() gets triggered. This is where we retrieve the latitude and longitude of the center of map(because that is where the marker resides) and pass it into the method getAddressFromLocation() which will eventually do the reverse geocoding.

    setOnCameraIdleListener将侦听地图上的移动/拖动。 运动结束后,将触发onCameraIdle()方法。 在这里,我们检索地图中心的纬度和经度(因为这是标记所在的位置),并将其传递到方法getAddressFromLocation() ,该方法最终将进行反向地理编码。
  7. The method getFromLocation(double latitude, double longitude, int maxResults) returns a List of Addresses for the current location.

    方法getFromLocation(double latitude, double longitude, int maxResults)返回当前位置的地址列表。
  8. Within the Address object, the method getAddressLine(int index) returns a line of the address numbered by the given index or null if no address exists.

    Address对象中,方法getAddressLine(int index)返回由给定索引编号的地址行;如果不存在地址,则返回null。
  9. We append that address to a StringBuilder which is eventually displayed in the TextView.

    我们将该地址附加到StringBuilder,该字符串最终显示在TextView中。
  10. getMaxAddressLineIndex() returns the largest index currently in use to specify an address line.

    getMaxAddressLineIndex()返回当前用于指定地址行的最大索引。
  11. There are several other important details of an address that can retrieved too. Some of them are listed below:
    • getThoroughfare() : This is the street, which contains the delivery point. If it doesn’t exist null would be returned.
    • getSubThoroughfare() : When a thoroughfare name exists more than once within a town, subThoroughfare name is used for additional information.
    • getLocality() and getSublocality() : Returns the locality of the address, for example “Mountain View” and sub locality respectively if available or null.
    • getFeatureName() : Returns the nearest landmark name if available or null.
    • getCountryName() getCountryCode() : Returns the country name and country code respectively.

    地址的其他一些重要细节也可以检索。 下面列出了其中一些:
    • getThoroughfare() :这是一条街道,其中包含交付点。 如果不存在,则返回null。
    • getSubThoroughfare() :当一个城镇的通途名称不止一次存在时,subThoroughfare名称将用于其他信息。
    • getLocality()getSublocality() :返回地址的局部性,例如,如果可用,则分别返回“ Mountain View”和子局部性,或者返回null。
    • getFeatureName() :返回最近的地标名称(如果有)或为null。
    • getCountryName() getCountryCode() :分别返回国家名称和国家代码。
  12. Clicking the CardView would launch the PlaceAutoComplete service from the Google Places API.

    点击CardView将从Google Places API启动PlaceAutoComplete服务。
  13. We use the PlaceAutocomplete.IntentBuilder to create Intent and pass the Mode as full screen.

    我们使用PlaceAutocomplete.IntentBuilder创建Intent并将Mode作为全屏传递。
  14. The selected place is returned in the onActivityResult() which is eventually displayed in the TextView. The latitude and longitude of the Place are returned as place.getLatLng() which is eventually zoomed into the center of the screen.

    所选位置将在onActivityResult()返回,该结果最终将显示在TextView中。 将Place的纬度和经度作为place.getLatLng()返回,最终将其缩放到屏幕的中心。

The output of the android reverse geocoding application in action is given below.

实际操作中的android反向地理编码应用程序的输出如下。

This brings an end to android Geocoder example tutorial. You can download the final Android Reverse Geocoding Project from the link below and make sure to add your own API in the meta-data tag inside AndroidManifest.xml file.

这结束了android Geocoder示例教程。 您可以从下面的链接下载最终的Android反向地理编码项目 ,并确保在AndroidManifest.xml文件内的meta-data标签中添加自己的API。

References : Geocoder, Address, Place Autocomplete.

参考: 地址 解析器地址 ,位置自动完成功能

翻译自: https://www.journaldev.com/15676/android-geocoder-reverse-geocoding

geocoder

 类似资料: