Android cihazın mevcut konumunu bulmayı ve bu konumdaki yerin (işletme veya diğer önemli yerler) ayrıntılarını görüntülemeyi öğrenin. Android için Haritalar SDK'sı, Android için Places SDK ve Google Play Hizmetleri Location API'lerindeki çok kaynaklı konum sağlayıcıyı kullanarak Android uygulaması oluşturmak için bu eğitim videosunu izleyin.
Kodu alın
GitHub'dan Google Haritalar Android API v2 Samples deposunu kopyalayın veya indirin.
Etkinliğin Java sürümünü görüntüleyin:
// Copyright 2020 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package com.example.currentplacedetailsonmap; import android.content.DialogInterface; import android.content.pm.PackageManager; import android.location.Location; import android.os.Bundle; import android.util.Log; import android.util.TypedValue; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.FrameLayout; import android.widget.TextView; import android.widget.Toast; import androidx.annotation.NonNull; import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AppCompatActivity; import androidx.core.app.ActivityCompat; import androidx.core.content.ContextCompat; import androidx.core.graphics.Insets; import androidx.core.view.ViewCompat; import androidx.core.view.WindowInsetsCompat; import com.google.android.gms.location.FusedLocationProviderClient; import com.google.android.gms.location.LocationServices; 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.CameraPosition; import com.google.android.gms.maps.model.LatLng; import com.google.android.gms.maps.model.Marker; import com.google.android.gms.maps.model.MarkerOptions; import com.google.android.gms.tasks.OnCompleteListener; import com.google.android.gms.tasks.Task; import com.google.android.libraries.places.api.Places; import com.google.android.libraries.places.api.model.CircularBounds; import com.google.android.libraries.places.api.model.Place; import com.google.android.libraries.places.api.net.PlacesClient; import com.google.android.libraries.places.api.net.SearchNearbyRequest; import com.google.android.libraries.places.api.net.SearchNearbyResponse; import java.util.ArrayList; import java.util.Arrays; import java.util.List; /** An activity that displays a map showing the place at the device's current location. */ public class MapsActivityCurrentPlace extends AppCompatActivity implements OnMapReadyCallback { private static final String TAG = MapsActivityCurrentPlace.class.getSimpleName(); private GoogleMap map; private CameraPosition cameraPosition; // The entry point to the Places API. private PlacesClient placesClient; // The entry point to the Fused Location Provider. private FusedLocationProviderClient fusedLocationProviderClient; // A default location (Sydney, Australia) and default zoom to use when location permission is // not granted. private final LatLng defaultLocation = new LatLng(-33.8523341, 151.2106085); private static final int DEFAULT_ZOOM = 15; private static final int PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION = 1; private boolean locationPermissionGranted; // The geographical location where the device is currently located. That is, the last-known // location retrieved by the Fused Location Provider or set via long press. Location lastKnownLocation; // Keys for storing activity state. private static final String KEY_CAMERA_POSITION = "camera_position"; private static final String KEY_LOCATION = "location"; // Used for selecting the current place. private static final int M_MAX_ENTRIES = 5; private static final double SEARCH_RADIUS_METERS = 100.0; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Retrieve location and camera position from saved instance state. if (savedInstanceState != null) { lastKnownLocation = savedInstanceState.getParcelable(KEY_LOCATION); cameraPosition = savedInstanceState.getParcelable(KEY_CAMERA_POSITION); } // Retrieve the content view that renders the map. setContentView(R.layout.activity_maps); ViewCompat.setOnApplyWindowInsetsListener( getWindow().getDecorView(), (v, insets) -> { Insets systemBars = insets.getInsets( WindowInsetsCompat.Type.systemBars() | WindowInsetsCompat.Type.displayCutout()); View actionBarContainer = getWindow() .getDecorView() .findViewById(androidx.appcompat.R.id.action_bar_container); if (actionBarContainer != null) { actionBarContainer.setPadding( actionBarContainer.getPaddingLeft(), systemBars.top, actionBarContainer.getPaddingRight(), actionBarContainer.getPaddingBottom()); } TypedValue typedValue = new TypedValue(); int actionBarHeight = getTheme() .resolveAttribute( android.R.attr.actionBarSize, typedValue, true) ? TypedValue.complexToDimensionPixelSize( typedValue.data, getResources().getDisplayMetrics()) : 0; if (map != null) { map.setPadding(0, systemBars.top + actionBarHeight, 0, systemBars.bottom); } return insets; }); // Construct a PlacesClient Places.initializeWithNewPlacesApiEnabled(getApplicationContext(), BuildConfig.MAPS_API_KEY); placesClient = Places.createClient(this); // Construct a FusedLocationProviderClient. fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(this); // Build the map. SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map); mapFragment.getMapAsync(this); } /** Saves the state of the map when the activity is paused. */ @Override protected void onSaveInstanceState(Bundle outState) { if (map != null) { outState.putParcelable(KEY_CAMERA_POSITION, map.getCameraPosition()); outState.putParcelable(KEY_LOCATION, lastKnownLocation); } super.onSaveInstanceState(outState); } /** * Sets up the options menu. * * @param menu The options menu. * @return Boolean. */ @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.current_place_menu, menu); return true; } /** * Handles a click on the menu option to get a place. * * @param item The menu item to handle. * @return Boolean. */ @Override public boolean onOptionsItemSelected(MenuItem item) { if (item.getItemId() == R.id.option_get_place) { showCurrentPlace(); } return true; } /** * Manipulates the map when it's available. This callback is triggered when the map is ready to * be used. */ @Override public void onMapReady(GoogleMap map) { this.map = map; // Use a custom info window adapter to handle multiple lines of text in the // info window contents. this.map.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, (FrameLayout) findViewById(R.id.map), false); TextView title = infoWindow.findViewById(R.id.title); title.setText(marker.getTitle()); TextView snippet = infoWindow.findViewById(R.id.snippet); snippet.setText(marker.getSnippet()); return infoWindow; } }); // Allow moving the current location with a long press on the map to easily // demo and discover nearby places anywhere in the world. this.map.setOnMapLongClickListener(this::setCustomLocation); // Prompt the user for permission. getLocationPermission(); WindowInsetsCompat rootInsets = ViewCompat.getRootWindowInsets(getWindow().getDecorView()); if (rootInsets != null) { Insets systemBars = rootInsets.getInsets( WindowInsetsCompat.Type.systemBars() | WindowInsetsCompat.Type.displayCutout()); TypedValue typedValue = new TypedValue(); int actionBarHeight = getTheme().resolveAttribute(android.R.attr.actionBarSize, typedValue, true) ? TypedValue.complexToDimensionPixelSize( typedValue.data, getResources().getDisplayMetrics()) : 0; this.map.setPadding(0, systemBars.top + actionBarHeight, 0, systemBars.bottom); } // 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(); } /** Gets the current location of the device, and positions the map's camera. */ 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 (locationPermissionGranted) { Task<Location> locationResult = fusedLocationProviderClient.getLastLocation(); locationResult.addOnCompleteListener( this, new OnCompleteListener<Location>() { @Override public void onComplete(@NonNull Task<Location> task) { if (task.isSuccessful()) { // Set the map's camera position to the current location of the // device. lastKnownLocation = task.getResult(); if (lastKnownLocation != null) { map.moveCamera( CameraUpdateFactory.newLatLngZoom( new LatLng( lastKnownLocation.getLatitude(), lastKnownLocation.getLongitude()), DEFAULT_ZOOM)); } } else { Log.d(TAG, "Current location is null. Using defaults."); Log.e(TAG, "Exception: %s", task.getException()); map.moveCamera( CameraUpdateFactory.newLatLngZoom( defaultLocation, DEFAULT_ZOOM)); map.getUiSettings().setMyLocationButtonEnabled(false); } } }); } } catch (SecurityException e) { Log.e("Exception: %s", e.getMessage(), e); } } /** Prompts the user for permission to use the device location. */ 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) { locationPermissionGranted = true; } else { ActivityCompat.requestPermissions( this, new String[] {android.Manifest.permission.ACCESS_FINE_LOCATION}, PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION); } } /** Handles the result of the request for location permissions. */ @Override public void onRequestPermissionsResult( int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { locationPermissionGranted = false; if (requestCode == PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION) { // If request is cancelled, the // result arrays are empty. if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { locationPermissionGranted = true; } } else { super.onRequestPermissionsResult(requestCode, permissions, grantResults); } updateLocationUI(); } /** * UI representation of a place item to display in the selection dialog and map marker. * * <p>It is good practice to decouple the external data/backend model ({@link Place}) from the * UI layer. The UI should be as free of logic as possible: it receives presentation-ready data * (non-null coordinates, ready-to-display title and snippet strings) so that dialogs and map * overlays remain simple, predictable, and testable. */ static class PlaceItemUiModel { final String title; final String snippet; final LatLng position; PlaceItemUiModel(String title, String snippet, LatLng position) { this.title = title; this.snippet = snippet; this.position = position; } } /** * Maps an external {@link Place} domain model into a display-ready {@link PlaceItemUiModel}. * * <p>The mapper encapsulates all data normalization, default value fallbacks (such as fallback * titles), and string formatting (such as appending third-party attributions to the address). * Keeping this transformation logic in the mapper prevents business and formatting logic from * leaking into the UI components. Returns {@code null} if essential coordinates are missing. */ private PlaceItemUiModel toUiModel(Place place) { return toUiModel(place, getString(R.string.default_info_title)); } static PlaceItemUiModel toUiModel(Place place, String defaultTitle) { if (place.getLocation() == null) { return null; } String title = place.getDisplayName() != null ? place.getDisplayName() : defaultTitle; StringBuilder snippet = new StringBuilder(); if (place.getFormattedAddress() != null) { snippet.append(place.getFormattedAddress()); } if (place.getAttributions() != null && !place.getAttributions().isEmpty()) { if (snippet.length() > 0) { snippet.append("\n"); } snippet.append(String.join("\n", place.getAttributions())); } return new PlaceItemUiModel(title, snippet.toString(), place.getLocation()); } /** * Prompts the user to select the current place from a list of likely places, and shows the * current place on the map - provided the user has granted location permission. */ private void showCurrentPlace() { if (map == null) { return; } if (lastKnownLocation != null && "manual".equals(lastKnownLocation.getProvider())) { locationPermissionGranted = true; } if (locationPermissionGranted) { // Use fields to define the data types to return. List<Place.Field> placeFields = Arrays.asList( Place.Field.DISPLAY_NAME, Place.Field.FORMATTED_ADDRESS, Place.Field.LOCATION); // Search around the device's last-known location, falling back to the center of the // map if the location is not available yet. LatLng center = lastKnownLocation != null ? new LatLng( lastKnownLocation.getLatitude(), lastKnownLocation.getLongitude()) : map.getCameraPosition().target; CircularBounds searchArea = CircularBounds.newInstance(center, SEARCH_RADIUS_METERS); // Use the builder to create a SearchNearbyRequest that returns the closest places // first. SearchNearbyRequest request = SearchNearbyRequest.builder(searchArea, placeFields) .setMaxResultCount(M_MAX_ENTRIES) .setRankPreference(SearchNearbyRequest.RankPreference.DISTANCE) .build(); // Get the likely places - that is, the businesses and other points of interest that // are closest to the device's current location. final Task<SearchNearbyResponse> placeResult = placesClient.searchNearby(request); placeResult.addOnCompleteListener( new OnCompleteListener<SearchNearbyResponse>() { @Override public void onComplete(@NonNull Task<SearchNearbyResponse> task) { if (task.isSuccessful() && task.getResult() != null) { List<Place> responsePlaces = task.getResult().getPlaces(); int count = Math.min(responsePlaces.size(), M_MAX_ENTRIES); List<PlaceItemUiModel> likelyPlaces = new ArrayList<>(); for (int i = 0; i < count; i++) { PlaceItemUiModel model = toUiModel(responsePlaces.get(i)); if (model != null) { likelyPlaces.add(model); } } // Show a dialog offering the user the list of likely places, and // add a marker at the selected place. MapsActivityCurrentPlace.this.openPlacesDialog(likelyPlaces); } 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. map.addMarker( new MarkerOptions() .title(getString(R.string.default_info_title)) .position(defaultLocation) .snippet(getString(R.string.default_info_snippet))); // Prompt the user for permission. getLocationPermission(); } } /** Displays a form allowing the user to select a place from a list of likely places. */ void openPlacesDialog(List<PlaceItemUiModel> likelyPlaces) { if (likelyPlaces.isEmpty()) { Toast.makeText( this, "No places found nearby. Long-press on the map to choose another location.", Toast.LENGTH_LONG) .show(); return; } // 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. PlaceItemUiModel selectedPlace = likelyPlaces.get(which); // Add a marker for the selected place, with an info window // showing information about that place. map.addMarker( new MarkerOptions() .title(selectedPlace.title) .position(selectedPlace.position) .snippet(selectedPlace.snippet)); // Position the map's camera at the location of the marker. map.moveCamera( CameraUpdateFactory.newLatLngZoom( selectedPlace.position, DEFAULT_ZOOM)); } }; // Display the dialog. String[] titles = new String[likelyPlaces.size()]; for (int i = 0; i < likelyPlaces.size(); i++) { titles[i] = likelyPlaces.get(i).title; } new AlertDialog.Builder(this) .setTitle(R.string.pick_place) .setItems(titles, listener) .show(); } /** Updates the map's UI settings based on whether the user has granted location permission. */ private void updateLocationUI() { if (map == null) { return; } try { if (locationPermissionGranted) { map.setMyLocationEnabled(true); map.getUiSettings().setMyLocationButtonEnabled(true); } else { map.setMyLocationEnabled(false); map.getUiSettings().setMyLocationButtonEnabled(false); lastKnownLocation = null; } } catch (SecurityException e) { Log.e("Exception: %s", e.getMessage()); } } /** Updates the current location and searches for places around the specified coordinate. */ void setCustomLocation(LatLng latLng) { Location location = new Location("manual"); location.setLatitude(latLng.latitude); location.setLongitude(latLng.longitude); lastKnownLocation = location; if (map != null) { map.animateCamera(CameraUpdateFactory.newLatLng(latLng)); } showCurrentPlace(); } }
Etkinliğin Kotlin sürümünü görüntüleyin:
// Copyright 2020 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package com.example.currentplacedetailsonmap import android.Manifest import android.annotation.SuppressLint import android.content.DialogInterface import android.content.pm.PackageManager import android.location.Location import android.os.Bundle import android.util.Log import android.util.TypedValue import android.view.Menu import android.view.MenuItem import android.view.View import android.widget.FrameLayout import android.widget.TextView import android.widget.Toast import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AppCompatActivity import androidx.core.app.ActivityCompat import androidx.core.content.ContextCompat import androidx.core.view.ViewCompat import androidx.core.view.WindowInsetsCompat import com.google.android.gms.location.FusedLocationProviderClient import com.google.android.gms.location.LocationServices import com.google.android.gms.maps.CameraUpdateFactory import com.google.android.gms.maps.GoogleMap import com.google.android.gms.maps.GoogleMap.InfoWindowAdapter import com.google.android.gms.maps.OnMapReadyCallback import com.google.android.gms.maps.SupportMapFragment import com.google.android.gms.maps.model.CameraPosition import com.google.android.gms.maps.model.LatLng import com.google.android.gms.maps.model.Marker import com.google.android.gms.maps.model.MarkerOptions import com.google.android.libraries.places.api.Places import com.google.android.libraries.places.api.model.CircularBounds import com.google.android.libraries.places.api.model.Place import com.google.android.libraries.places.api.net.PlacesClient import com.google.android.libraries.places.api.net.SearchNearbyRequest /** * An activity that displays a map showing the place at the device's current location. */ class MapsActivityCurrentPlace : AppCompatActivity(), OnMapReadyCallback { private var map: GoogleMap? = null private var cameraPosition: CameraPosition? = null internal var selectedMarker: Marker? = null // The entry point to the Places API. private lateinit var placesClient: PlacesClient // The entry point to the Fused Location Provider. private lateinit var fusedLocationProviderClient: FusedLocationProviderClient // A default location (Sydney, Australia) and default zoom to use when location permission is // not granted. private val defaultLocation = LatLng(-33.8523341, 151.2106085) private var locationPermissionGranted = false // The geographical location where the device is currently located. That is, the last-known // location retrieved by the Fused Location Provider or set via long press. internal var lastKnownLocation: Location? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // Retrieve location and camera position from saved instance state. if (savedInstanceState != null) { lastKnownLocation = savedInstanceState.getParcelable(KEY_LOCATION) cameraPosition = savedInstanceState.getParcelable(KEY_CAMERA_POSITION) } // Retrieve the content view that renders the map. setContentView(R.layout.activity_maps) ViewCompat.setOnApplyWindowInsetsListener(window.decorView) { _, insets -> val systemBars = insets.getInsets( WindowInsetsCompat.Type.systemBars() or WindowInsetsCompat.Type.displayCutout(), ) val actionBarContainer = window.decorView.findViewById<View>(androidx.appcompat.R.id.action_bar_container) actionBarContainer?.setPadding( actionBarContainer.paddingLeft, systemBars.top, actionBarContainer.paddingRight, actionBarContainer.paddingBottom, ) val typedValue = TypedValue() val actionBarHeight = if (theme.resolveAttribute(android.R.attr.actionBarSize, typedValue, true)) { TypedValue.complexToDimensionPixelSize(typedValue.data, resources.displayMetrics) } else { 0 } map?.setPadding(0, systemBars.top + actionBarHeight, 0, systemBars.bottom) insets } // Construct a PlacesClient Places.initializeWithNewPlacesApiEnabled(applicationContext, BuildConfig.MAPS_API_KEY) placesClient = Places.createClient(this) // Construct a FusedLocationProviderClient. fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(this) // Build the map. val mapFragment = supportFragmentManager .findFragmentById(R.id.map) as SupportMapFragment? mapFragment?.getMapAsync(this) } /** * Saves the state of the map when the activity is paused. */ override fun onSaveInstanceState(outState: Bundle) { map?.let { map -> outState.putParcelable(KEY_CAMERA_POSITION, map.cameraPosition) outState.putParcelable(KEY_LOCATION, lastKnownLocation) } super.onSaveInstanceState(outState) } /** * Sets up the options menu. * @param menu The options menu. * @return Boolean. */ override fun onCreateOptionsMenu(menu: Menu): Boolean { menuInflater.inflate(R.menu.current_place_menu, menu) return true } /** * Handles a click on the menu option to get a place. * @param item The menu item to handle. * @return Boolean. */ override fun onOptionsItemSelected(item: MenuItem): Boolean { if (item.itemId == R.id.option_get_place) { showCurrentPlace() } return true } /** * Manipulates the map when it's available. * This callback is triggered when the map is ready to be used. */ override fun onMapReady(map: GoogleMap) { this.map = map // Use a custom info window adapter to handle multiple lines of text in the // info window contents. this.map?.setInfoWindowAdapter(object : InfoWindowAdapter { // Return null here, so that getInfoContents() is called next. override fun getInfoWindow(arg0: Marker): View? = null override fun getInfoContents(marker: Marker): View { // Inflate the layouts for the info window, title and snippet. val infoWindow = layoutInflater.inflate( R.layout.custom_info_contents, findViewById<FrameLayout>(R.id.map), false, ) val title = infoWindow.findViewById<TextView>(R.id.title) title.text = marker.title val snippet = infoWindow.findViewById<TextView>(R.id.snippet) snippet.text = marker.snippet return infoWindow } }) // Allow moving the current location with a long press on the map to easily // demo and discover nearby places anywhere in the world. this.map?.setOnMapLongClickListener { latLng -> setCustomLocation(latLng) } // Prompt the user for permission. getLocationPermission() val insets = ViewCompat.getRootWindowInsets(window.decorView) ?.getInsets(WindowInsetsCompat.Type.systemBars() or WindowInsetsCompat.Type.displayCutout()) val topInset = insets?.top ?: 0 val bottomInset = insets?.bottom ?: 0 val typedValue = TypedValue() val actionBarHeight = if (theme.resolveAttribute(android.R.attr.actionBarSize, typedValue, true)) { TypedValue.complexToDimensionPixelSize(typedValue.data, resources.displayMetrics) } else { 0 } this.map?.setPadding(0, topInset + actionBarHeight, 0, bottomInset) // 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() } /** * Gets the current location of the device, and positions the map's camera. */ @SuppressLint("MissingPermission") private fun 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 (locationPermissionGranted) { val locationResult = fusedLocationProviderClient.lastLocation locationResult.addOnCompleteListener(this) { task -> if (task.isSuccessful) { // Set the map's camera position to the current location of the device. lastKnownLocation = task.result if (lastKnownLocation != null) { map?.moveCamera( CameraUpdateFactory.newLatLngZoom( LatLng( lastKnownLocation!!.latitude, lastKnownLocation!!.longitude, ), DEFAULT_ZOOM.toFloat(), ), ) } } else { Log.d(TAG, "Current location is null. Using defaults.") Log.e(TAG, "Exception: %s", task.exception) map?.moveCamera( CameraUpdateFactory .newLatLngZoom(defaultLocation, DEFAULT_ZOOM.toFloat()), ) map?.uiSettings?.isMyLocationButtonEnabled = false } } } } catch (e: SecurityException) { Log.e("Exception: %s", e.message, e) } } /** * Prompts the user for permission to use the device location. */ private fun 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.applicationContext, Manifest.permission.ACCESS_FINE_LOCATION, ) == PackageManager.PERMISSION_GRANTED ) { locationPermissionGranted = true } else { ActivityCompat.requestPermissions( this, arrayOf(Manifest.permission.ACCESS_FINE_LOCATION), PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION, ) } } /** * Handles the result of the request for location permissions. */ override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) { locationPermissionGranted = false when (requestCode) { PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION -> { // If request is cancelled, the result arrays are empty. if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED ) { locationPermissionGranted = true } } else -> super.onRequestPermissionsResult(requestCode, permissions, grantResults) } updateLocationUI() } private fun Place.toUiModel(): PlaceItemUiModel? = toPlaceItemUiModel(this, getString(R.string.default_info_title)) /** * Prompts the user to select the current place from a list of likely places, and shows the * current place on the map - provided the user has granted location permission. */ private fun showCurrentPlace() { val map = map ?: return if (lastKnownLocation?.provider == "manual") { locationPermissionGranted = true } if (locationPermissionGranted) { // Use fields to define the data types to return. val placeFields = listOf( Place.Field.DISPLAY_NAME, Place.Field.FORMATTED_ADDRESS, Place.Field.LOCATION, ) // Search around the device's last-known location, falling back to the center of // the map if the location is not available yet. val center = lastKnownLocation?.let { LatLng(it.latitude, it.longitude) } ?: map.cameraPosition.target val searchArea = CircularBounds.newInstance(center, SEARCH_RADIUS_METERS) // Use the builder to create a SearchNearbyRequest that returns the closest places // first. val request = SearchNearbyRequest.builder(searchArea, placeFields) .setMaxResultCount(M_MAX_ENTRIES) .setRankPreference(SearchNearbyRequest.RankPreference.DISTANCE) .build() // Get the likely places - that is, the businesses and other points of interest that // are closest to the device's current location. val placeResult = placesClient.searchNearby(request) placeResult.addOnCompleteListener { task -> if (task.isSuccessful && task.result != null) { val likelyPlaces = task.result.places .take(M_MAX_ENTRIES) .mapNotNull { it.toUiModel() } // Show a dialog offering the user the list of likely places, and add a // marker at the selected place. openPlacesDialog(likelyPlaces) } else { Log.e(TAG, "Exception: %s", task.exception) } } } 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. map.addMarker( MarkerOptions() .title(getString(R.string.default_info_title)) .position(defaultLocation) .snippet(getString(R.string.default_info_snippet)), ) // Prompt the user for permission. getLocationPermission() } } /** * Displays a form allowing the user to select a place from a list of likely places. */ internal fun openPlacesDialog(likelyPlaces: List<PlaceItemUiModel>) { if (likelyPlaces.isEmpty()) { Toast.makeText( this, "No places found nearby. Long-press on the map to choose another location.", Toast.LENGTH_LONG, ).show() return } // Ask the user to choose the place where they are now. val listener = DialogInterface.OnClickListener { _, which -> // The "which" argument contains the position of the selected item. val selectedPlace = likelyPlaces[which] // Add a marker for the selected place, with an info window // showing information about that place. selectedMarker = map?.addMarker( MarkerOptions() .title(selectedPlace.title) .position(selectedPlace.position) .snippet(selectedPlace.snippet), ) // Position the map's camera at the location of the marker. map?.moveCamera( CameraUpdateFactory.newLatLngZoom( selectedPlace.position, DEFAULT_ZOOM.toFloat(), ), ) } // Display the dialog. val titles = likelyPlaces.map { it.title }.toTypedArray() AlertDialog.Builder(this) .setTitle(R.string.pick_place) .setItems(titles, listener) .show() } /** * Updates the map's UI settings based on whether the user has granted location permission. */ @SuppressLint("MissingPermission") private fun updateLocationUI() { if (map == null) { return } try { if (locationPermissionGranted) { map?.isMyLocationEnabled = true map?.uiSettings?.isMyLocationButtonEnabled = true } else { map?.isMyLocationEnabled = false map?.uiSettings?.isMyLocationButtonEnabled = false lastKnownLocation = null getLocationPermission() } } catch (e: SecurityException) { Log.e("Exception: %s", e.message, e) } } /** * Updates the current location and searches for places around the specified coordinate. */ internal fun setCustomLocation(latLng: LatLng) { val location = Location("manual").apply { latitude = latLng.latitude longitude = latLng.longitude } lastKnownLocation = location map?.animateCamera(CameraUpdateFactory.newLatLng(latLng)) showCurrentPlace() } companion object { private val TAG = MapsActivityCurrentPlace::class.java.simpleName private const val DEFAULT_ZOOM = 15 private const val PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION = 1 // Keys for storing activity state. private const val KEY_CAMERA_POSITION = "camera_position" private const val KEY_LOCATION = "location" // Used for selecting the current place. private const val M_MAX_ENTRIES = 5 private const val SEARCH_RADIUS_METERS = 100.0 } } /** * UI representation of a place item to display in the selection dialog and map marker. * * It is good practice to decouple the external data/backend model ([Place]) from the UI layer. * The UI should be as free of logic as possible: it receives presentation-ready data (non-null * coordinates, ready-to-display title and snippet strings) so that dialogs and map overlays * remain simple, predictable, and testable. */ internal data class PlaceItemUiModel(val title: String, val snippet: String, val position: LatLng) /** * Maps an external [Place] domain model into a display-ready [PlaceItemUiModel]. * * The mapper encapsulates all data normalization, default value fallbacks (such as fallback * titles), and string formatting (such as appending third-party attributions to the address). * Keeping this transformation logic in the mapper prevents business and formatting logic * from leaking into the UI components. Returns `null` if essential coordinates are missing. */ internal fun toPlaceItemUiModel(place: Place, defaultTitle: String): PlaceItemUiModel? { val position = place.location ?: return null val title = place.displayName ?: defaultTitle val snippet = buildString { place.formattedAddress?.let { append(it) } place.attributions?.takeIf { it.isNotEmpty() }?.let { if (isNotEmpty()) append("\n") append(it.joinToString("\n")) } } return PlaceItemUiModel(title = title, snippet = snippet, position = position) }
Geliştirme projenizi oluşturma

Android Studio'da eğitim projesini oluşturmak için aşağıdaki adımları uygulayın.
- Android Studio'yu indirip yükleyin.
- Android Studio'ya Google Play Hizmetleri paketini ekleyin.
- Bu eğiticiyi okumaya başladığınızda yapmadıysanız Google Haritalar Android API v2 Örnekleri deposunu kopyalayın veya indirin.
Eğitim projesini içe aktarın:
- Android Studio'da File > New > Import Project'i (Dosya > Yeni > Projeyi İçe Aktar) seçin.
- Google Haritalar Android API v2 Örnekleri deposunu indirdikten sonra kaydettiğiniz konuma gidin.
- CurrentPlaceDetailsOnMap projesini şu konumda bulabilirsiniz:
PATH-TO-SAVED-REPO/android-samples/tutorials/java/CurrentPlaceDetailsOnMap(Java) veya
PATH-TO-SAVED-REPO/android-samples/tutorials/kotlin/CurrentPlaceDetailsOnMap(Kotlin) - Proje dizinini seçin ve Open'ı (Aç) tıklayın. Android Studio, Gradle derleme aracını kullanarak projenizi derler.
Gerekli API'leri etkinleştirme ve API anahtarı alma
Bu eğitimi tamamlamak için gerekli API'lerin etkinleştirildiği bir Google Cloud projeniz ve Android için Haritalar SDK'sını kullanma yetkisine sahip bir API anahtarınız olmalıdır. Daha fazla bilgi için:
Etkinleştirdiğiniz API'leri görüntülemek için Cloud Console'da Google Haritalar Platformu sayfasına gidin ve projenizi seçin:
Google Haritalar Platformu sayfasına gidinProjenizde Places API'nin etkinleştirildiğini görmüyorsanız etkinleştirmeniz gerekir:
Places API'yi etkinleştirmeAPI anahtarınıza kısıtlama ekliyorsanız Places API'yi anahtara eklediğinizden emin olun. Daha fazla bilgi için API Anahtarlarını Kullanma konusunu inceleyin.
API anahtarını uygulamanıza ekleme
- Projenizin
local.propertiesdosyasını açın. Aşağıdaki dizeyi ekleyin ve
YOUR_API_KEYkısmını API anahtarınızın değeriyle değiştirin:MAPS_API_KEY=YOUR_API_KEY
Uygulamanızı derlediğinizde Android için Secrets Gradle Plugin, API anahtarını kopyalar ve Android manifest dosyasında derleme değişkeni olarak kullanılabilir hale getirir.
Uygulamanızı derleyip çalıştırma
Android cihazınızı bilgisayarınıza bağlayın. Android cihazınızda geliştirici seçeneklerini etkinleştirmek ve sisteminizi cihazı algılayacak şekilde yapılandırmak için talimatları uygulayın.
Alternatif olarak, sanal bir cihaz yapılandırmak için Android Sanal Cihaz (AVD) Yöneticisi'ni kullanabilirsiniz. Emülatör seçerken Google API'lerini içeren bir görüntü seçtiğinizden emin olun. Daha fazla bilgi için Android Studio Projesi Oluşturma başlıklı makaleyi inceleyin.
- Android Studio'da Run (Çalıştır) menü seçeneğini (veya oynat düğmesi simgesini) tıklayın. İstendiğinde bir cihaz seçin.
Android Studio, uygulamayı derlemek için Gradle'ı çağırır ve ardından uygulamayı cihazda veya emülatörde çalıştırır. Bu sayfadaki resme benzer şekilde, mevcut konumunuzun etrafında ortalanmış bir dizi işaretçi içeren bir harita görürsünüz.
- Mevcut konumunuzun yakınındaki yerlerin (bir işletme veya başka bir önemli yer) listesini açmak için Yer Al'ı seçin. Yerlerin listesini görmek için istendiğinde konum izni vermeniz gerekir.
- Listeden bir yer seçin. Seçilen yer için haritaya bir işaretçi eklenir.
Sorun Giderme:
- Harita görmüyorsanız yukarıda açıklandığı gibi bir API anahtarı aldığınızdan ve bunu uygulamaya eklediğinizden emin olun. API anahtarıyla ilgili hata mesajları için Android Studio'nun Android Monitor bölümündeki günlüğü kontrol edin.
- Haritada yalnızca Sydney Harbour Bridge'de (uygulamada belirtilen varsayılan konum) tek bir işaretçi gösteriliyorsa uygulamaya konum izni verdiğinizden emin olun. Uygulama, Android izinleri kılavuzunda açıklanan kalıbı izleyerek çalışma zamanında konum izni ister. İzinleri doğrudan cihazda Ayarlar > Uygulamalar > uygulama adı > İzinler > Konum'u seçerek de ayarlayabilirsiniz. Kodunuzda izinleri nasıl işleyeceğinizle ilgili ayrıntılar için aşağıdaki uygulamanızda konum izni isteme kılavuzuna bakın.
- Günlükleri görüntülemek ve uygulamada hata ayıklamak için Android Studio hata ayıklama araçlarını kullanın.
Kodu anlama
Eğitimin bu bölümünde, benzer bir uygulamayı nasıl oluşturacağınızı anlamanıza yardımcı olmak için CurrentPlaceDetailsOnMap uygulamasının en önemli kısımları açıklanmaktadır.
Places API istemcisini örneklendirme
Bu nesneler, Android için Yerler SDK'sının birincil giriş noktalarıdır:
Placessınıfı, Android için Yerler SDK'sı istemcilerini oluşturur ve yönetir.PlacesClientarayüzü, cihazın mevcut konumunu ve bu konumun yakınındaki yerleri alır.
LocationServices arayüzü, Android konum hizmetleri için ana giriş noktasıdır.
API'leri kullanmak için parçanızın veya etkinliğinizin onCreate() yönteminde aşağıdakileri yapın:
Placesnesnesi başlatın.PlacesClientnesnesi oluşturun.FusedLocationProviderClientnesnesi oluşturun.
Örneğin:
Java
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // ... // Retrieve the content view that renders the map. setContentView(R.layout.activity_maps); // Construct a PlacesClient Places.initialize(getApplicationContext(), getString(R.string.maps_api_key)); placesClient = Places.createClient(this); // Construct a FusedLocationProviderClient. fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(this); }
Kotlin
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // ... // Retrieve the content view that renders the map. setContentView(R.layout.activity_maps) // Construct a PlacesClient Places.initialize(applicationContext, getString(R.string.maps_api_key)) placesClient = Places.createClient(this) // Construct a FusedLocationProviderClient. fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(this) }
Konum izni iste
Uygulamanız, cihazın konumunu belirlemek ve kullanıcının haritadaki Konumum düğmesine dokunmasına izin vermek için konum izni istemelidir.
Bu eğitimde, tam konum izni istemek için gereken kod sağlanmaktadır. Daha fazla bilgi için Android izinleri kılavuzunu inceleyin.
İzni, Android manifest dosyanızdaki
<manifest>öğesinin alt öğesi olarak ekleyin:<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.currentplacedetailsonmap"> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> </manifest>
Uygulamanızda çalışma zamanında istenen izinleri isteyerek kullanıcıya konum izni verme veya reddetme fırsatı sunun. Aşağıdaki kod, kullanıcının tam konum izni verip vermediğini kontrol eder. Yoksa izin ister:
Java
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) { locationPermissionGranted = true; } else { ActivityCompat.requestPermissions( this, new String[] {android.Manifest.permission.ACCESS_FINE_LOCATION}, PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION); } }
Kotlin
private fun 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.applicationContext, Manifest.permission.ACCESS_FINE_LOCATION, ) == PackageManager.PERMISSION_GRANTED ) { locationPermissionGranted = true } else { ActivityCompat.requestPermissions( this, arrayOf(Manifest.permission.ACCESS_FINE_LOCATION), PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION, ) } }
İzin isteğinin sonucunu işlemek için
onRequestPermissionsResult()geri çağırma işlevini geçersiz kılın:Java
@Override public void onRequestPermissionsResult( int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { locationPermissionGranted = false; if (requestCode == PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION) { // If request is cancelled, the // result arrays are empty. if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { locationPermissionGranted = true; } } else { super.onRequestPermissionsResult(requestCode, permissions, grantResults); } updateLocationUI(); }
Kotlin
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) { locationPermissionGranted = false when (requestCode) { PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION -> { // If request is cancelled, the result arrays are empty. if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED ) { locationPermissionGranted = true } } else -> super.onRequestPermissionsResult(requestCode, permissions, grantResults) } updateLocationUI() }
Bu eğitimin sonraki bölümlerinde
updateLocationUI()yöntemi açıklanmaktadır.
Harita ekleme
Android için Haritalar SDK'sını kullanarak harita görüntüleme
Etkinliğinizin düzen dosyasına (
activity_maps.xml) bir<fragment>öğesi ekleyin. Bu öğe, harita için kapsayıcı görevi görecek veGoogleMapnesnesine erişim sağlayacak birSupportMapFragmenttanımlar. Eğitimde, Android çerçevesinin önceki sürümleriyle geriye dönük uyumluluk sağlamak için harita parçasının Android Destek Kitaplığı sürümü kullanılır.<!-- Copyright 2020 Google LLC Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. --> <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" />
Etkinliğinizin
onCreate()yönteminde, düzen dosyasını içerik görünümü olarak ayarlayın:Java
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Retrieve the content view that renders the map. setContentView(R.layout.activity_maps); }
Kotlin
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // Retrieve the content view that renders the map. setContentView(R.layout.activity_maps) }
GoogleMapnesnesi kullanılabilir olduğunda haritayı ayarlamak içinOnMapReadyCallbackarayüzünü uygulayın veonMapReady()yöntemini geçersiz kılın:Java
@Override public void onMapReady(GoogleMap map) { this.map = map; // ... // 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(); }
Kotlin
override fun onMapReady(map: GoogleMap) { this.map = map // ... // 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() }
Etkinliğinizin
onCreate()yönteminde,FragmentManager.findFragmentById()yöntemini çağırarak harita parçası için bir tutma yeri alın. Ardından, harita geri çağırma işlevine kaydolmak içingetMapAsync()yöntemini kullanın:Java
SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map); mapFragment.getMapAsync(this);
Kotlin
val mapFragment = supportFragmentManager .findFragmentById(R.id.map) as SupportMapFragment? mapFragment?.getMapAsync(this)
Haritada konum kontrollerini ayarlamak için bir
updateLocationUI()yöntemi yazın. Kullanıcı konum izni verdiyse Konumum katmanını ve haritadaki ilgili kontrolü etkinleştirin. Aksi takdirde katmanı ve kontrolü devre dışı bırakın ve mevcut konumu null olarak ayarlayın:Java
private void updateLocationUI() { if (map == null) { return; } try { if (locationPermissionGranted) { map.setMyLocationEnabled(true); map.getUiSettings().setMyLocationButtonEnabled(true); } else { map.setMyLocationEnabled(false); map.getUiSettings().setMyLocationButtonEnabled(false); lastKnownLocation = null; } } catch (SecurityException e) { Log.e("Exception: %s", e.getMessage()); } }
Kotlin
@SuppressLint("MissingPermission") private fun updateLocationUI() { if (map == null) { return } try { if (locationPermissionGranted) { map?.isMyLocationEnabled = true map?.uiSettings?.isMyLocationButtonEnabled = true } else { map?.isMyLocationEnabled = false map?.uiSettings?.isMyLocationButtonEnabled = false lastKnownLocation = null getLocationPermission() } } catch (e: SecurityException) { Log.e("Exception: %s", e.message, e) } }
Android cihazın konumunu alma ve haritayı konumlandırma
Cihazın bilinen son konumunu bulmak için çok kaynaklı konum sağlayıcıyı kullanın, ardından haritayı konumlandırmak için bu konumu kullanın. Eğitimde ihtiyacınız olan kod sağlanır. Cihazın konumunu alma hakkında daha fazla bilgi için Google Play Hizmetleri konum API'lerindeki çok kaynaklı konum sağlayıcı kılavuzuna bakın.
Java
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 (locationPermissionGranted) { Task<Location> locationResult = fusedLocationProviderClient.getLastLocation(); locationResult.addOnCompleteListener( this, new OnCompleteListener<Location>() { @Override public void onComplete(@NonNull Task<Location> task) { if (task.isSuccessful()) { // Set the map's camera position to the current location of the // device. lastKnownLocation = task.getResult(); if (lastKnownLocation != null) { map.moveCamera( CameraUpdateFactory.newLatLngZoom( new LatLng( lastKnownLocation.getLatitude(), lastKnownLocation.getLongitude()), DEFAULT_ZOOM)); } } else { Log.d(TAG, "Current location is null. Using defaults."); Log.e(TAG, "Exception: %s", task.getException()); map.moveCamera( CameraUpdateFactory.newLatLngZoom( defaultLocation, DEFAULT_ZOOM)); map.getUiSettings().setMyLocationButtonEnabled(false); } } }); } } catch (SecurityException e) { Log.e("Exception: %s", e.getMessage(), e); } }
Kotlin
@SuppressLint("MissingPermission") private fun 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 (locationPermissionGranted) { val locationResult = fusedLocationProviderClient.lastLocation locationResult.addOnCompleteListener(this) { task -> if (task.isSuccessful) { // Set the map's camera position to the current location of the device. lastKnownLocation = task.result if (lastKnownLocation != null) { map?.moveCamera( CameraUpdateFactory.newLatLngZoom( LatLng( lastKnownLocation!!.latitude, lastKnownLocation!!.longitude, ), DEFAULT_ZOOM.toFloat(), ), ) } } else { Log.d(TAG, "Current location is null. Using defaults.") Log.e(TAG, "Exception: %s", task.exception) map?.moveCamera( CameraUpdateFactory .newLatLngZoom(defaultLocation, DEFAULT_ZOOM.toFloat()), ) map?.uiSettings?.isMyLocationButtonEnabled = false } } } } catch (e: SecurityException) { Log.e("Exception: %s", e.message, e) } }
Mevcut yeri alma
Cihazın mevcut konumunda bulunabilecek yerlerin listesini almak için Android için Yerler SDK'sını kullanın. Bu bağlamda yer, bir işletme veya başka bir önemli yerdir.
Bu eğitimde, kullanıcı Yeri Al düğmesini tıkladığında mevcut yer alınır. Kullanıcıya, aralarından seçim yapabileceği olası yerlerin listesini sunar ve ardından seçilen yerin konumuna haritada bir işaretçi ekler. Eğitimde, Android için Yerler SDK'sı ile etkileşim kurmak için gereken kod sağlanır. Daha fazla bilgi için mevcut yeri alma kılavuzuna bakın.
- Seçenekler menüsü için bir düzen dosyası (
current_place_menu.xml) oluşturun ve seçenekler menüsünü ayarlamak içinonCreateOptionsMenu()yöntemini geçersiz kılın. Kod için ekteki örnek uygulamaya bakın. - Kullanıcı Get Place (Yeri Al) seçeneğini tıkladığında mevcut yeri almak için
onOptionsItemSelected()yöntemini geçersiz kılın:Java
@Override public boolean onOptionsItemSelected(MenuItem item) { if (item.getItemId() == R.id.option_get_place) { showCurrentPlace(); } return true; }
Kotlin
override fun onOptionsItemSelected(item: MenuItem): Boolean { if (item.itemId == R.id.option_get_place) { showCurrentPlace() } return true }
Cihazın mevcut konumundaki olası yerlerin listesini almak için bir
showCurrentPlace()yöntemi oluşturun:Java
private void showCurrentPlace() { if (map == null) { return; } // ... if (locationPermissionGranted) { // Use fields to define the data types to return. List<Place.Field> placeFields = Arrays.asList( Place.Field.DISPLAY_NAME, Place.Field.FORMATTED_ADDRESS, Place.Field.LOCATION); // Search around the device's last-known location, falling back to the center of the // map if the location is not available yet. LatLng center = lastKnownLocation != null ? new LatLng( lastKnownLocation.getLatitude(), lastKnownLocation.getLongitude()) : map.getCameraPosition().target; CircularBounds searchArea = CircularBounds.newInstance(center, SEARCH_RADIUS_METERS); // Use the builder to create a SearchNearbyRequest that returns the closest places // first. SearchNearbyRequest request = SearchNearbyRequest.builder(searchArea, placeFields) .setMaxResultCount(M_MAX_ENTRIES) .setRankPreference(SearchNearbyRequest.RankPreference.DISTANCE) .build(); // Get the likely places - that is, the businesses and other points of interest that // are closest to the device's current location. final Task<SearchNearbyResponse> placeResult = placesClient.searchNearby(request); placeResult.addOnCompleteListener( new OnCompleteListener<SearchNearbyResponse>() { @Override public void onComplete(@NonNull Task<SearchNearbyResponse> task) { if (task.isSuccessful() && task.getResult() != null) { List<Place> responsePlaces = task.getResult().getPlaces(); int count = Math.min(responsePlaces.size(), M_MAX_ENTRIES); List<PlaceItemUiModel> likelyPlaces = new ArrayList<>(); for (int i = 0; i < count; i++) { PlaceItemUiModel model = toUiModel(responsePlaces.get(i)); if (model != null) { likelyPlaces.add(model); } } // Show a dialog offering the user the list of likely places, and // add a marker at the selected place. MapsActivityCurrentPlace.this.openPlacesDialog(likelyPlaces); } 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. map.addMarker( new MarkerOptions() .title(getString(R.string.default_info_title)) .position(defaultLocation) .snippet(getString(R.string.default_info_snippet))); // Prompt the user for permission. getLocationPermission(); } }
Kotlin
private fun showCurrentPlace() { val map = map ?: return // ... if (locationPermissionGranted) { // Use fields to define the data types to return. val placeFields = listOf( Place.Field.DISPLAY_NAME, Place.Field.FORMATTED_ADDRESS, Place.Field.LOCATION, ) // Search around the device's last-known location, falling back to the center of // the map if the location is not available yet. val center = lastKnownLocation?.let { LatLng(it.latitude, it.longitude) } ?: map.cameraPosition.target val searchArea = CircularBounds.newInstance(center, SEARCH_RADIUS_METERS) // Use the builder to create a SearchNearbyRequest that returns the closest places // first. val request = SearchNearbyRequest.builder(searchArea, placeFields) .setMaxResultCount(M_MAX_ENTRIES) .setRankPreference(SearchNearbyRequest.RankPreference.DISTANCE) .build() // Get the likely places - that is, the businesses and other points of interest that // are closest to the device's current location. val placeResult = placesClient.searchNearby(request) placeResult.addOnCompleteListener { task -> if (task.isSuccessful && task.result != null) { val likelyPlaces = task.result.places .take(M_MAX_ENTRIES) .mapNotNull { it.toUiModel() } // Show a dialog offering the user the list of likely places, and add a // marker at the selected place. openPlacesDialog(likelyPlaces) } else { Log.e(TAG, "Exception: %s", task.exception) } } } 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. map.addMarker( MarkerOptions() .title(getString(R.string.default_info_title)) .position(defaultLocation) .snippet(getString(R.string.default_info_snippet)), ) // Prompt the user for permission. getLocationPermission() } }
Kullanıcının olası yerler listesinden bir yer seçmesine olanak tanıyan bir form görüntülemek için
openPlacesDialog()yöntemi oluşturun. Seçilen yer için haritaya bir işaretçi ekleyin. İşaretçi içeriği, yerin adını ve adresini ve API'nin sağladığı tüm atıfları içerir:Java
void openPlacesDialog(List<PlaceItemUiModel> likelyPlaces) { // ... // 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. PlaceItemUiModel selectedPlace = likelyPlaces.get(which); // Add a marker for the selected place, with an info window // showing information about that place. map.addMarker( new MarkerOptions() .title(selectedPlace.title) .position(selectedPlace.position) .snippet(selectedPlace.snippet)); // Position the map's camera at the location of the marker. map.moveCamera( CameraUpdateFactory.newLatLngZoom( selectedPlace.position, DEFAULT_ZOOM)); } }; // Display the dialog. String[] titles = new String[likelyPlaces.size()]; for (int i = 0; i < likelyPlaces.size(); i++) { titles[i] = likelyPlaces.get(i).title; } new AlertDialog.Builder(this) .setTitle(R.string.pick_place) .setItems(titles, listener) .show(); }
Kotlin
internal fun openPlacesDialog(likelyPlaces: List<PlaceItemUiModel>) { // ... // Ask the user to choose the place where they are now. val listener = DialogInterface.OnClickListener { _, which -> // The "which" argument contains the position of the selected item. val selectedPlace = likelyPlaces[which] // Add a marker for the selected place, with an info window // showing information about that place. selectedMarker = map?.addMarker( MarkerOptions() .title(selectedPlace.title) .position(selectedPlace.position) .snippet(selectedPlace.snippet), ) // Position the map's camera at the location of the marker. map?.moveCamera( CameraUpdateFactory.newLatLngZoom( selectedPlace.position, DEFAULT_ZOOM.toFloat(), ), ) } // Display the dialog. val titles = likelyPlaces.map { it.title }.toTypedArray() AlertDialog.Builder(this) .setTitle(R.string.pick_place) .setItems(titles, listener) .show() }
Bilgi penceresi içeriği için özel bir düzen oluşturun. Bu sayede, bilgi penceresinde birden fazla satır içerik gösterilebilir. Öncelikle, bilgi penceresi başlığı için bir metin görünümü ve snippet (yani bilgi penceresinin metin içeriği) için başka bir metin görünümü içeren bir XML düzen dosyası (
custom_info_contents.xml) ekleyin:<?xml version="1.0" encoding="utf-8"?> <!-- Copyright 2020 Google LLC Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. --> <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>
Düzeni genişletmek ve bilgi penceresi içeriğini yüklemek için
InfoWindowAdapterarayüzünü uygulayın:Java
// Use a custom info window adapter to handle multiple lines of text in the // info window contents. this.map.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, (FrameLayout) findViewById(R.id.map), false); TextView title = infoWindow.findViewById(R.id.title); title.setText(marker.getTitle()); TextView snippet = infoWindow.findViewById(R.id.snippet); snippet.setText(marker.getSnippet()); return infoWindow; } });
Kotlin
// Use a custom info window adapter to handle multiple lines of text in the // info window contents. this.map?.setInfoWindowAdapter(object : InfoWindowAdapter { // Return null here, so that getInfoContents() is called next. override fun getInfoWindow(arg0: Marker): View? = null override fun getInfoContents(marker: Marker): View { // Inflate the layouts for the info window, title and snippet. val infoWindow = layoutInflater.inflate( R.layout.custom_info_contents, findViewById<FrameLayout>(R.id.map), false, ) val title = infoWindow.findViewById<TextView>(R.id.title) title.text = marker.title val snippet = infoWindow.findViewById<TextView>(R.id.snippet) snippet.text = marker.snippet return infoWindow } })
Haritanın durumunu kaydetme
Haritanın kamera konumunu ve cihaz konumunu kaydetme Kullanıcı bir Android cihazı döndürdüğünde veya yapılandırma değişiklikleri yaptığında Android çerçevesi, harita etkinliğini yok eder ve yeniden oluşturur. Sorunsuz bir kullanıcı deneyimi sağlamak için ilgili uygulama durumunu depolamak ve gerektiğinde geri yüklemek iyi bir yöntemdir.
Bu eğitimde, haritanın durumunu kaydetmek için gereken tüm kodlar sağlanır. Daha fazla bilgi için savedInstanceState paketi kılavuzuna bakın.
Harita etkinliğinizde, etkinlik durumunu depolamak için anahtar değerler oluşturun:
Java
private static final String KEY_CAMERA_POSITION = "camera_position"; private static final String KEY_LOCATION = "location";
Kotlin
private const val KEY_CAMERA_POSITION = "camera_position" private const val KEY_LOCATION = "location"
Etkinlik duraklatıldığında durumu kaydetmek için
onSaveInstanceState()geri çağırma işlevini uygulayın:Java
@Override protected void onSaveInstanceState(Bundle outState) { if (map != null) { outState.putParcelable(KEY_CAMERA_POSITION, map.getCameraPosition()); outState.putParcelable(KEY_LOCATION, lastKnownLocation); } super.onSaveInstanceState(outState); }
Kotlin
override fun onSaveInstanceState(outState: Bundle) { map?.let { map -> outState.putParcelable(KEY_CAMERA_POSITION, map.cameraPosition) outState.putParcelable(KEY_LOCATION, lastKnownLocation) } super.onSaveInstanceState(outState) }
Etkinliğinizin
onCreate()yönteminde, cihazın konumunu ve daha önce kaydedilmişse haritanın kamera konumunu alın:Java
// Retrieve location and camera position from saved instance state. if (savedInstanceState != null) { lastKnownLocation = savedInstanceState.getParcelable(KEY_LOCATION); cameraPosition = savedInstanceState.getParcelable(KEY_CAMERA_POSITION); }
Kotlin
if (savedInstanceState != null) { lastKnownLocation = savedInstanceState.getParcelable(KEY_LOCATION) cameraPosition = savedInstanceState.getParcelable(KEY_CAMERA_POSITION) }