Memilih Tempat Saat Ini dan Menampilkan Detail pada Peta

Tutorial ini menunjukkan cara menemukan lokasi perangkat Android saat ini dan menampilkan detail tempat (bisnis atau lokasi menarik lainnya) di lokasi tersebut. Ikuti tutorial ini untuk membuat aplikasi Android menggunakan Maps SDK for Android, Places SDK for Android, dan penyedia lokasi fusi di Location API layanan Google Play.

Mendapatkan kode

Lakukan clone atau download repositori Google Maps Android API v2 Samples dari GitHub.

Menyiapkan project pengembangan

Ikuti langkah-langkah berikut untuk membuat project tutorial di Android Studio.

  1. Download dan instal Android Studio.
  2. Tambahkan paket layanan Google Play ke Android Studio.
  3. Lakukan clone atau download repositori Google Maps Android API v2 Samples jika Anda belum melakukannya saat mulai membaca tutorial ini.
  4. Impor project tutorial:

    • Di Android Studio, pilih File > New > Import Project.
    • Buka lokasi tempat Anda menyimpan repositori Google Maps Android API v2 Samples setelah mendownloadnya.
    • Temukan project CurrentPlaceDetailsOnMap di lokasi ini:
      PATH-TO-SAVED-REPO/android-samples/tutorials/CurrentPlaceDetailsOnMap
    • Pilih direktori project, lalu klik OK. Android Studio akan membuat project Anda menggunakan alat build Gradle.

Mendapatkan kunci API dan mengaktifkan API yang diperlukan

Untuk menyelesaikan tutorial ini, Anda memerlukan kunci Google API yang diizinkan untuk menggunakan Maps SDK for Android dan Places SDK for Android.

Klik tombol di bawah untuk mendapatkan kunci dan mengaktifkan API.

Mulai

Untuk mengetahui detail selengkapnya, lihat panduan lengkap untuk mendapatkan kunci API.

Menambahkan kunci API ke aplikasi

  1. Edit file gradle.properties project Anda.
  2. Tempelkan kunci API ke nilai properti GOOGLE_MAPS_API_KEY:

    GOOGLE_MAPS_API_KEY=PASTE-YOUR-API-KEY-HERE

    Saat Anda membuat aplikasi, Gradle akan menyalin kunci API ke dalam manifes Android aplikasi. File build.gradle aplikasi berisi baris berikut, yang memetakan string google_maps_key dalam manifes ke GOOGLE_MAPS_API_KEY properti gradle:

    resValue "string", "google_maps_key",
            (project.findProperty("GOOGLE_MAPS_API_KEY") ?: "")
    

Membuat dan menjalankan aplikasi

  1. Hubungkan perangkat Android ke komputer Anda. Ikuti petunjuk untuk mengaktifkan opsi developer di perangkat Android Anda dan mengonfigurasikan sistem guna mendeteksi perangkat tersebut. (Atau, Anda dapat menggunakan Android Virtual Device (AVD) Manager untuk mengonfigurasikan perangkat virtual. Saat memilih emulator, pastikan Anda memilih image yang berisi Google API. Untuk mengetahui detail selengkapnya, lihat panduan memulai.)
  2. Di Android Studio, klik opsi menu Run (atau ikon tombol putar). Pilih perangkat saat diminta.

Android Studio memanggil Gradle untuk membuat aplikasi, lalu menjalankan aplikasi tersebut di perangkat atau di emulator. Anda akan melihat peta dengan sejumlah penanda yang dipusatkan di sekitar lokasi Anda saat ini, mirip dengan gambar di halaman ini.

Pemecahan masalah:

  • Jika Anda tidak melihat peta, pastikan bahwa Anda telah mendapatkan kunci API dan menambahkannya ke aplikasi, seperti yang dideskripsikan di atas. Periksa log Android Monitor di Android Studio untuk melihat pesan error tentang kunci API.
  • Jika peta tersebut hanya menampilkan satu penanda yang berada pada Sydney Harbour Bridge (lokasi default yang ditetapkan dalam aplikasi), periksa apakah Anda telah memberikan izin akses lokasi ke aplikasi. Aplikasi akan meminta izin akses lokasi pada waktu proses, dengan mengikuti pola yang dijelaskan dalam panduan izin Android. Perhatikan bahwa Anda juga dapat langsung menetapkan izin di perangkat, dengan memilih Setelan > Aplikasi > nama aplikasi > Izin > Lokasi. Guna mengetahui cara menangani izin dalam kode Anda selengkapnya, lihat panduan di bawah untuk meminta izin akses lokasi di aplikasi Anda.
  • Gunakan alat debug Android Studio untuk melihat log dan melakukan debug pada aplikasi.

Memahami kode

Bagian tutorial ini menjelaskan bagian yang paling signifikan dari aplikasi CurrentPlaceDetailsOnMap untuk membantu Anda memahami cara membuat aplikasi serupa.

Membuat instance klien Places API

Antarmuka berikut menyediakan titik entri utama ke Places SDK for Android:

  • GeoDataClient menyediakan akses ke database tempat lokal dan informasi bisnis milik Google.
  • PlaceDetectionClient menyediakan akses cepat ke tempat perangkat saat ini, dan menawarkan peluang untuk melaporkan lokasi perangkat di tempat tertentu.

Antarmuka LocationServices adalah titik entri utama untuk layanan lokasi Android.

Untuk menggunakan API, buat instance GeoDataClient, PlaceDetectionClient, dan FusedLocationProviderClient dalam metode onCreate() fragmen atau aktivitas Anda, seperti yang ditunjukkan dalam contoh kode berikut:

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

    // Construct a GeoDataClient.
    mGeoDataClient = Places.getGeoDataClient(this, null);

    // Construct a PlaceDetectionClient.
    mPlaceDetectionClient = Places.getPlaceDetectionClient(this, null);

    // Construct a FusedLocationProviderClient.
    mFusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(this);
}

Meminta izin akses lokasi

Aplikasi Anda harus meminta izin lokasi agar dapat menentukan lokasi perangkat dan memungkinkan pengguna mengetuk tombol Lokasiku pada peta.

Tutorial ini menyediakan kode yang Anda butuhkan untuk meminta izin akses lokasi halus. Untuk mengetahui detail selengkapnya, lihat panduan izin Android.

  1. Tambahkan izin sebagai turunan elemen <manifest> dalam manifes Android Anda:

    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.example.currentplacedetailsonmap">
        <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    </manifest>
    
  2. Minta izin waktu proses dalam aplikasi Anda, dengan memberikan kesempatan kepada pengguna untuk memberikan atau menolak izin akses lokasi. Kode berikut akan memeriksa apakah pengguna telah memberikan izin akses lokasi halus. Jika tidak, kode ini akan meminta izin tersebut:

    private void getLocationPermission() {
        /*
         * Request location permission, so that we can get the location of the
         * device. The result of the permission request is handled by a callback,
         * onRequestPermissionsResult.
         */
        if (ContextCompat.checkSelfPermission(this.getApplicationContext(),
                android.Manifest.permission.ACCESS_FINE_LOCATION)
                == PackageManager.PERMISSION_GRANTED) {
            mLocationPermissionGranted = true;
        } else {
            ActivityCompat.requestPermissions(this,
                    new String[]{android.Manifest.permission.ACCESS_FINE_LOCATION},
                    PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION);
        }
    }
    
  3. Ganti callback onRequestPermissionsResult() untuk menangani hasil permintaan izin:

    @Override
    public void onRequestPermissionsResult(int requestCode,
                                           @NonNull String[] permissions,
                                           @NonNull int[] grantResults) {
        mLocationPermissionGranted = false;
        switch (requestCode) {
            case PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION: {
                // If request is cancelled, the result arrays are empty.
                if (grantResults.length > 0
                        && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    mLocationPermissionGranted = true;
                }
            }
        }
        updateLocationUI();
    }
    

    Bagian selanjutnya dari tutorial ini menjelaskan metode updateLocationUI().

Menambahkan peta

Tampilkan peta, menggunakan Maps SDK for Android.

  1. Tambahkan elemen <fragment> ke file tata letak aktivitas Anda, activity_maps.xml. Elemen ini menentukan SupportMapFragment agar berfungsi sebagai penampung untuk peta dan untuk memberikan akses ke objek GoogleMap. Tutorial ini menggunakan fragmen peta versi Android Support Library untuk memastikan kompatibilitas mundur dengan framework Android versi lama.

    <fragment xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:id="@+id/map"
        android:name="com.google.android.gms.maps.SupportMapFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context="com.example.currentplacedetailsonmap.MapsActivityCurrentPlace" />
    
    
  2. Dalam metode onCreate() aktivitas, tetapkan file tata letak sebagai tampilan konten:

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_maps);
    }
    
  3. Terapkan antarmuka OnMapReadyCallback dan ganti metode onMapReady() untuk menyiapkan peta saat objek GoogleMap tersedia:

    public void onMapReady(GoogleMap map) {
        mMap = map;
    
        // Do other setup activities here too, as described elsewhere in this tutorial.
    
        // Turn on the My Location layer and the related control on the map.
        updateLocationUI();
    
        // Get the current location of the device and set the position of the map.
        getDeviceLocation();
    }
    
  4. Dalam metode onCreate() aktivitas Anda, dapatkan handle ke fragmen peta dengan memanggil FragmentManager.findFragmentById(). Selanjutnya, gunakan getMapAsync() untuk mendaftarkan callback peta:

    SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
            .findFragmentById(R.id.map);
    mapFragment.getMapAsync(this);
    
  5. Tulis metode updateLocationUI() untuk menetapkan kontrol lokasi pada peta. Jika pengguna telah memberikan izin akses lokasi, aktifkan lapisan My Location dan kontrol terkait pada peta, atau nonaktifkan lapisan dan kontrol tersebut, lalu tetapkan lokasi saat ini ke null:

    private void updateLocationUI() {
        if (mMap == null) {
            return;
        }
        try {
            if (mLocationPermissionGranted) {
                mMap.setMyLocationEnabled(true);
                mMap.getUiSettings().setMyLocationButtonEnabled(true);
            } else {
                mMap.setMyLocationEnabled(false);
                mMap.getUiSettings().setMyLocationButtonEnabled(false);
                mLastKnownLocation = null;
                getLocationPermission();
            }
        } catch (SecurityException e)  {
            Log.e("Exception: %s", e.getMessage());
        }
    }
    

Mendapatkan lokasi perangkat Android dan memosisikan peta

Gunakan penyedia lokasi fusi untuk menemukan lokasi terakhir perangkat, lalu gunakan lokasi tersebut untuk memosisikan peta. Tutorial ini memberikan kode yang Anda butuhkan. Agar dapat mengetahui detail selengkapnya tentang mendapatkan lokasi perangkat, lihat panduan untuk penyedia lokasi fusi di Location API layanan Google Play.

private void getDeviceLocation() {
    /*
     * Get the best and most recent location of the device, which may be null in rare
     * cases when a location is not available.
     */
    try {
        if (mLocationPermissionGranted) {
            Task locationResult = mFusedLocationProviderClient.getLastLocation();
            locationResult.addOnCompleteListener(this, new OnCompleteListener() {
                @Override
                public void onComplete(@NonNull Task task) {
                    if (task.isSuccessful()) {
                        // Set the map's camera position to the current location of the device.
                        mLastKnownLocation = task.getResult();
                        mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(
                                new LatLng(mLastKnownLocation.getLatitude(),
                                        mLastKnownLocation.getLongitude()), DEFAULT_ZOOM));
                    } else {
                        Log.d(TAG, "Current location is null. Using defaults.");
                        Log.e(TAG, "Exception: %s", task.getException());
                        mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(mDefaultLocation, DEFAULT_ZOOM));
                        mMap.getUiSettings().setMyLocationButtonEnabled(false);
                    }
                }
            });
        }
    } catch(SecurityException e)  {
        Log.e("Exception: %s", e.getMessage());
    }
}

Mendapatkan tempat saat ini

Gunakan Places SDK for Android untuk mendapatkan daftar kemungkinan tempat di lokasi perangkat saat ini. Dalam konteks ini, tempat bisa berupa bisnis atau lokasi menarik lainnya.

Tutorial ini mendapatkan tempat saat ini jika pengguna mengklik tombol Dapatkan Tempat. Tutorial memberi pengguna daftar kemungkinan tempat untuk dipilih, lalu menambahkan penanda pada peta di lokasi tempat yang dipilih. Tutorial ini memberikan kode yang diperlukan untuk berinteraksi dengan Places SDK for Android. Untuk mengetahui detail selengkapnya, lihat panduan untuk mendapatkan tempat saat ini.

  1. Buat file tata letak (current_place_menu.xml) untuk menu opsi, dan ganti metode onCreateOptionsMenu(), untuk menyiapkan menu opsi. Lihat contoh aplikasi yang disertakan untuk kode tersebut.
  2. Ganti metode onOptionsItemSelected() untuk mendapatkan tempat saat ini saat pengguna mengklik opsi Dapatkan Tempat:
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        if (item.getItemId() == R.id.option_get_place) {
            showCurrentPlace();
        }
        return true;
    }
    
  3. Buat metode showCurrentPlace() untuk mendapatkan daftar kemungkinan tempat di lokasi perangkat saat ini:

    private void showCurrentPlace() {
        if (mMap == null) {
            return;
        }
    
        if (mLocationPermissionGranted) {
            // Use fields to define the data types to return.
            List<Place.Field> placeFields = Arrays.asList(Place.Field.NAME, Place.Field.ADDRESS,
                    Place.Field.LAT_LNG);
    
            // Use the builder to create a FindCurrentPlaceRequest.
            FindCurrentPlaceRequest request =
                    FindCurrentPlaceRequest.newInstance(placeFields);
    
            // Get the likely places - that is, the businesses and other points of interest that
            // are the best match for the device's current location.
            @SuppressWarnings("MissingPermission") final
            Task<FindCurrentPlaceResponse> placeResult =
                    mPlacesClient.findCurrentPlace(request);
            placeResult.addOnCompleteListener (new OnCompleteListener<FindCurrentPlaceResponse>() {
                @Override
                public void onComplete(@NonNull Task<FindCurrentPlaceResponse> task) {
                    if (task.isSuccessful() && task.getResult() != null) {
                        FindCurrentPlaceResponse likelyPlaces = task.getResult();
    
                        // Set the count, handling cases where less than 5 entries are returned.
                        int count;
                        if (likelyPlaces.getPlaceLikelihoods().size() < M_MAX_ENTRIES) {
                            count = likelyPlaces.getPlaceLikelihoods().size();
                        } else {
                            count = M_MAX_ENTRIES;
                        }
    
                        int i = 0;
                        mLikelyPlaceNames = new String[count];
                        mLikelyPlaceAddresses = new String[count];
                        mLikelyPlaceAttributions = new List[count];
                        mLikelyPlaceLatLngs = new LatLng[count];
    
                        for (PlaceLikelihood placeLikelihood : likelyPlaces.getPlaceLikelihoods()) {
                            // Build a list of likely places to show the user.
                            mLikelyPlaceNames[i] = placeLikelihood.getPlace().getName();
                            mLikelyPlaceAddresses[i] = placeLikelihood.getPlace().getAddress();
                            mLikelyPlaceAttributions[i] = placeLikelihood.getPlace()
                                    .getAttributions();
                            mLikelyPlaceLatLngs[i] = placeLikelihood.getPlace().getLatLng();
    
                            i++;
                            if (i > (count - 1)) {
                                break;
                            }
                        }
    
                        // Show a dialog offering the user the list of likely places, and add a
                        // marker at the selected place.
                        MapsActivityCurrentPlace.this.openPlacesDialog();
                    }
                    else {
                        Log.e(TAG, "Exception: %s", task.getException());
                    }
                }
            });
        } else {
            // The user has not granted permission.
            Log.i(TAG, "The user did not grant location permission.");
    
            // Add a default marker, because the user hasn't selected a place.
            mMap.addMarker(new MarkerOptions()
                    .title(getString(R.string.default_info_title))
                    .position(mDefaultLocation)
                    .snippet(getString(R.string.default_info_snippet)));
    
            // Prompt the user for permission.
            getLocationPermission();
        }
    }
    
  4. Buat metode openPlacesDialog() untuk menampilkan formulir yang memungkinkan pengguna memilih tempat dari daftar kemungkinan tempat. Tambahkan penanda pada peta untuk tempat yang dipilih. Konten penanda mencakup nama dan alamat tempat, dan setiap atribusi yang disediakan API:

    private void openPlacesDialog() {
        // Ask the user to choose the place where they are now.
        DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                // The "which" argument contains the position of the selected item.
                LatLng markerLatLng = mLikelyPlaceLatLngs[which];
                String markerSnippet = mLikelyPlaceAddresses[which];
                if (mLikelyPlaceAttributions[which] != null) {
                    markerSnippet = markerSnippet + "\n" + mLikelyPlaceAttributions[which];
                }
    
                // Add a marker for the selected place, with an info window
                // showing information about that place.
                mMap.addMarker(new MarkerOptions()
                        .title(mLikelyPlaceNames[which])
                        .position(markerLatLng)
                        .snippet(markerSnippet));
    
                // Position the map's camera at the location of the marker.
                mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(markerLatLng,
                        DEFAULT_ZOOM));
            }
        };
    
        // Display the dialog.
        AlertDialog dialog = new AlertDialog.Builder(this)
                .setTitle(R.string.pick_place)
                .setItems(mLikelyPlaceNames, listener)
                .show();
    }
    
  5. Buat tata letak kustom untuk konten jendela info. Hal ini memungkinkan menampilkan beberapa baris konten di jendela info. Pertama, tambahkan file tata letak XML, custom_info_contents.xml, yang berisi tampilan teks untuk judul jendela info, dan tampilan teks lainnya untuk cuplikan (yaitu konten tekstual dari jendela info):

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layoutDirection="locale"
        android:orientation="vertical">
        <TextView
            android:id="@+id/title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:textColor="#ff000000"
            android:textStyle="bold" />
    
        <TextView
            android:id="@+id/snippet"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textColor="#ff7f7f7f" />
    </LinearLayout>
    
    
  6. Terapkan antarmuka InfoWindowAdapter untuk meng-inflate tata letak dan memuat konten jendela info:

    @Override
    public void onMapReady(GoogleMap map) {
        // Do other setup activities here too, as described elsewhere in this tutorial.
        mMap.setInfoWindowAdapter(new GoogleMap.InfoWindowAdapter() {
    
        @Override
        // Return null here, so that getInfoContents() is called next.
        public View getInfoWindow(Marker arg0) {
            return null;
        }
    
        @Override
        public View getInfoContents(Marker marker) {
            // Inflate the layouts for the info window, title and snippet.
            View infoWindow = getLayoutInflater().inflate(R.layout.custom_info_contents, null);
    
            TextView title = ((TextView) infoWindow.findViewById(R.id.title));
            title.setText(marker.getTitle());
    
            TextView snippet = ((TextView) infoWindow.findViewById(R.id.snippet));
            snippet.setText(marker.getSnippet());
    
            return infoWindow;
          }
        });
    }
    

Menyimpan status peta

Simpan posisi kamera peta dan lokasi perangkat. Jika pengguna memutar perangkat Android, atau membuat perubahan konfigurasi, framework Android akan menghapus dan membuat kembali aktivitas peta. Untuk memastikan pengalaman pengguna yang lancar, sebaiknya simpan status aplikasi yang relevan dan pulihkan jika diperlukan.

Tutorial ini menyediakan semua kode yang Anda perlukan untuk menyimpan status peta. Untuk mengetahui detail selengkapnya, lihat panduan untuk paket savedInstanceState.

  1. Di aktivitas peta Anda, siapkan nilai kunci untuk menyimpan status aktivitas:

    private static final String KEY_CAMERA_POSITION = "camera_position";
    private static final String KEY_LOCATION = "location";
    
  2. Terapkan callback onSaveInstanceState() untuk menyimpan status saat aktivitas dijeda:

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        if (mMap != null) {
            outState.putParcelable(KEY_CAMERA_POSITION, mMap.getCameraPosition());
            outState.putParcelable(KEY_LOCATION, mLastKnownLocation);
            super.onSaveInstanceState(outState);
        }
    }
    
  3. Dalam metode onCreate() aktivitas Anda, ambil lokasi perangkat dan posisi kamera peta jika sebelumnya disimpan:

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (savedInstanceState != null) {
            mCurrentLocation = savedInstanceState.getParcelable(KEY_LOCATION);
            mCameraPosition = savedInstanceState.getParcelable(KEY_CAMERA_POSITION);
        }
        ...
    }