Google Maps Platform 사이트에 가면 구글에서 제공하는 현재 위치 표시 소스가 있습니다.
이걸 이용해서 핸드폰에 현재 위치를 표시해 보도록 하겠습니다.
순서
1. 프로젝트 생성
2. Source Code 작성
2.1 AndroidManifest.xml
2.2 activity_main.xml
2.3 custom_info_contents.xml
2.4 current_place_menu.xml
2.5 strings.xml
2.6 build.gradle (Project)
2.7 build.gradle (Module)
2.8 MainActivity.java
3. 결과
4. APK
5. 전체 Source Code
5.1 AndroidManifest.xml
5.2 activity_main.xml
5.3 custom_info_contents.xml
5.4 current_place_menu.xml
5.5 strings.xml
5.6 build.gradle (Project)
5.7 build.gradle (Module)
5.8 MainActivity.java
사이트 주소
https://developers.google.com/maps/documentation/android-sdk/current-place-tutorial
에 접속하면 Source code와 함께 자세한 설명이 나와있습니다.
< > Show/Hide the Java code for the map activity.
이글을 클릭하면 소스 전체 보기가 펼쳐 집니다.
이 소스를 이용하여 프로젝트를 생성해 보겠습니다.
최종 결과는 현재 위치 표시와 근처 가계 정보가 나옵니다.
1. 프로젝트 생성
제목을 제외하고는 모두 기본 설정을 사용 했습니다.
package명을 이용하여
Google map API키에 등록 합니다.
API Key 생성과 등록에 대한 설명이 필요하면
[안드로이드] google map 사용을 위한 API 키 생성(2018.11)
기존 설명을 참고 하세요.
2. Source Code 작성
google 에서 제공하는 위치 정보에는 현재 위치에 대한 지역정보를 보여주도록 되어있어서 불필요한 설정들이 있습니다.
즉, 지역정보가 필요 없다면 생략해도 되는 소스들이 많이 있어 Resource 설정부분이 좀 복잡합니다.
일단은 모두 기록를 하였으니 필요없는 부분은 생략해서 사용하세요.
2.1 AndroidManifest.xml
권한 설정을 추가 합니다.
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"
/>
<uses-permission android:name="android.permission.INTERNET"/>
API 키도 추가해 줍니다.
<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="Axxxxxxxxxxxxxxxxxxxxxxxxxxxx_x1" />
<meta-data
android:name="com.google.android.gms.version"
android:value="@integer/google_play_services_version" />
2.2 activity_main.xml
layout에 fragment를 추가 합니다.
<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.3 custom_info_contents.xml
res>layout에 현재 위치의 지역정보를 보여주는 레이아웃 정보를 추가 합니다.
필요가 없다면 생략해도 됩니다.
<?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>
2.4 current_place_menu.xml
res>menu에 추가 합니다.
현재 위치의 지역정보를 보여주기 위한 메뉴입니다.
필요 없다면 생략 합니다.
<?xml version="1.0" encoding="utf-8"?><!--
Copyright (C) 2016 The Android Open Source Project
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.
-->
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/option_get_place"
android:title="@string/option_get_place"
app:showAsAction="always"/>
</menu>
2.5 strings.xml
메뉴등 텍스트 정보를 추가 합니다.
그냥 layout에 하드코딩 해도 됩니다.
<resources>
<string name="app_name">MyLocation</string>
<string name="default_info_title">Default Location</string>
<string name="default_info_snippet">No places found, because location permission is disabled.</string>
<string name="option_get_place">Get place</string>
<string name="pick_place">Choose a place</string>
</resources>
2.6 build.gradle (Project)
gms 추가
classpath 'com.google.gms:google-services:3.1.0'
2.7 build.gradle (Module)
gms 추가
implementation 'com.android.support:support-v4:27.1.1'
implementation 'com.google.android.gms:play-services-maps:15.0.0'
implementation 'com.google.android.gms:play-services-location:15.0.0'
implementation 'com.google.android.gms:play-services-places:15.0.0'
2.8 MainActivity.java
google 사이트 소스를 복사 합니다.
작성된 코드는 원본과 세곳이 다릅니다.
class 명이 기본 값이라 TAG 생성시 MainActivity를 사용했습니다.
private static final String TAG = MainActivity.class.getSimpleName();
기본 좌표를 한국으로 변경했습니다.
private final LatLng mDefaultLocation = new LatLng(37.56, 126.97);
layout도 기본설정이라 activity_main으로 사용합니다.
setContentView(R.layout.activity_main);
3. 결과
주말에 돌아다니다 캡처를 해봤습니다.
우측 상단 GET PLACE를 클릭하면 주변 정보를 보여줍니다.
4. APK
소스코드 작업이 귀찮을때는 다운받아 테스트 해보세요.
5. 전체 Source Code
5.1 AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="copycoding.tistory.mylocation">
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"
/>
<uses-permission android:name="android.permission.INTERNET"/>
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<meta-data
android:name="com.google.android.gms.version"
android:value="@integer/google_play_services_version"
/>
<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="Xxxxxxxxxxxxxxxxxxxxxxxxxxxx_x1"
/>
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"
/>
<category android:name="android.intent.category.LAUNCHER"
/>
</intent-filter>
</activity>
</application>
</manifest>
5.2 activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<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"
/>
</android.support.constraint.ConstraintLayout>
5.3 custom_info_contents.xml
<?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>
5.4 current_place_menu.xml
<?xml version="1.0" encoding="utf-8"?><!--
Copyright (C) 2016 The Android Open
Source Project
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.
-->
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/option_get_place"
android:title="@string/option_get_place"
app:showAsAction="always"/>
</menu>
5.5 strings.xml
<resources>
<string name="app_name">MyLocation</string>
<string name="default_info_title">Default Location</string>
<string name="default_info_snippet">No places found, because location permission is disabled.</string>
<string name="option_get_place">Get place</string>
<string name="pick_place">Choose a place</string>
</resources>
5.6 build.gradle (Project)
// Top-level build file where you can add
configuration options common to all sub-projects/modules.
buildscript {
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.2.1'
classpath 'com.google.gms:google-services:3.1.0'
// NOTE: Do not place your application dependencies here;
they belong
// in the individual module
build.gradle files
}
}
allprojects {
repositories {
google()
jcenter()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
5.7 build.gradle (Module)
apply plugin: 'com.android.application'
android {
compileSdkVersion 28
defaultConfig {
applicationId "copycoding.tistory.mylocation"
minSdkVersion 14
targetSdkVersion 28
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:appcompat-v7:28.0.0'
implementation 'com.android.support:support-v4:27.1.1'
implementation 'com.google.android.gms:play-services-maps:15.0.0'
implementation 'com.google.android.gms:play-services-location:15.0.0'
implementation 'com.google.android.gms:play-services-places:15.0.0'
implementation 'com.android.support.constraint:constraint-layout:1.1.3'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
}
5.8 MainActivity.java
package copycoding.tistory.mylocation;
import android.content.DialogInterface;
import android.content.pm.PackageManager;
import android.location.Location;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.TextView;
import com.google.android.gms.location.FusedLocationProviderClient;
import com.google.android.gms.location.LocationServices;
import com.google.android.gms.location.places.GeoDataClient;
import com.google.android.gms.location.places.PlaceDetectionClient;
import com.google.android.gms.location.places.PlaceLikelihood;
import com.google.android.gms.location.places.PlaceLikelihoodBufferResponse;
import com.google.android.gms.location.places.Places;
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 java.util.Locale;
public class MainActivity extends AppCompatActivity implements OnMapReadyCallback
{
private static final String TAG
= MainActivity.class.getSimpleName();
private GoogleMap mMap;
private CameraPosition mCameraPosition;
// The entry points to the Places API.
private GeoDataClient
mGeoDataClient;
private PlaceDetectionClient mPlaceDetectionClient;
// The entry point to the Fused Location Provider.
private FusedLocationProviderClient
mFusedLocationProviderClient;
// A default location (Sydney, Australia) and default
zoom to use when location permission is
// not granted.
private final LatLng mDefaultLocation = new LatLng(37.56, 126.97);
private static final int DEFAULT_ZOOM = 15;
private static final int PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION = 1;
private boolean mLocationPermissionGranted;
private Location mLastKnownLocation;
// 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 String[] mLikelyPlaceNames;
private String[] mLikelyPlaceAddresses;
private String[] mLikelyPlaceAttributions;
private LatLng[] mLikelyPlaceLatLngs;
@Override
protected void onCreate(Bundle
savedInstanceState) {
super.onCreate(savedInstanceState);
// Retrieve location and camera position from saved
instance state.
if (savedInstanceState
!= null) {
mLastKnownLocation = savedInstanceState.getParcelable(KEY_LOCATION);
mCameraPosition = savedInstanceState.getParcelable(KEY_CAMERA_POSITION);
}
setContentView(R.layout.activity_main);
mGeoDataClient = Places.getGeoDataClient(this, null);
mPlaceDetectionClient = Places.getPlaceDetectionClient(this, null);
mFusedLocationProviderClient = 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 (mMap != null) {
outState.putParcelable(KEY_CAMERA_POSITION, mMap.getCameraPosition());
outState.putParcelable(KEY_LOCATION, mLastKnownLocation);
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) {
mMap =
map;
// Use a custom info window adapter to handle multiple
lines of text in the
// info window contents.
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,
(FrameLayout) findViewById(R.id.map),
false);
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;
}
});
// Prompt the user for permission.
getLocationPermission();
// 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 (mLocationPermissionGranted) {
Task<Location>
locationResult = mFusedLocationProviderClient.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.
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());
}
}
/**
* 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) {
mLocationPermissionGranted = 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) {
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();
}
/**
* 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 (mMap == null) {
return;
}
if (mLocationPermissionGranted) {
// 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<PlaceLikelihoodBufferResponse> placeResult =
mPlaceDetectionClient.getCurrentPlace(null);
placeResult.addOnCompleteListener
(new OnCompleteListener<PlaceLikelihoodBufferResponse>()
{
@Override
public void onComplete(@NonNull Task<PlaceLikelihoodBufferResponse> task) {
if (task.isSuccessful() && task.getResult() != null) {
PlaceLikelihoodBufferResponse likelyPlaces = task.getResult();
// Set the count, handling cases where less
than 5 entries are returned.
int count;
if (likelyPlaces.getCount() < M_MAX_ENTRIES) {
count
= likelyPlaces.getCount();
} else {
count
= M_MAX_ENTRIES;
}
int i = 0;
mLikelyPlaceNames = new
String[count];
mLikelyPlaceAddresses = new String[count];
mLikelyPlaceAttributions = new
String[count];
mLikelyPlaceLatLngs = new LatLng[count];
for (PlaceLikelihood placeLikelihood :
likelyPlaces) {
// Build a list of likely places to show the
user.
mLikelyPlaceNames[i] = (String) placeLikelihood.getPlace().getName();
mLikelyPlaceAddresses[i] = (String) placeLikelihood.getPlace()
.getAddress();
mLikelyPlaceAttributions[i] = (String) placeLikelihood.getPlace()
.getAttributions();
mLikelyPlaceLatLngs[i]
= placeLikelihood.getPlace().getLatLng();
i++;
if (i > (count - 1))
{
break;
}
}
// Release the place likelihood buffer, to
avoid memory leaks.
likelyPlaces.release();
// Show a dialog offering the user the list of
likely places, and add a
// marker
at the selected place.
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();
}
}
/**
* Displays a form allowing the user
to select a place from a list of likely places.
*/
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();
}
/**
* Updates the map's UI settings
based on whether the user has granted location permission.
*/
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());
}
}
}
- copy coding -
'Android' 카테고리의 다른 글
안드로이드 나침반 만들기(TYPE_ACCELEROMETER, TYPE_MAGNETIC_FIELD) (0) | 2019.02.22 |
---|---|
[Android] 안드로이드 RotateAnimation 함수 이용 이미지 회전 (0) | 2019.02.21 |
[안드로이드] 안드로이드 데이터 저장 SharedPreferences 사용방법 (0) | 2019.01.24 |
[안드로이드] 안드로이드 스튜드오 프로젝트를 github에 업로드 하기 (2) | 2019.01.18 |
[안드로이드] github에있는 프로젝트 안드로이드 스튜디오로 힘들게 checkout 하기 (2) | 2019.01.16 |