현재 위치 지도 보여주기
대부분 위치기반 서비스를 활용한 앱은 사용자가 현재 위치를 잘 볼 수 있도록 지도를 이용해 위치를 나타낸다.
지도는 어떻게 보여주는 걸까?
안드로이드에서는 앱 화면 안에 지도를 넣을 수 있도록 맵프래그먼트(MapFragment)가 제공된다.
맵 프래그먼트는 새로운 방식의 구글맵 서비스 v2 기능을 사용할 수 있도록 추가된 기능으로 GooglePlay service 모듈을 사용한다.
다음은 맵프래그먼트를 추가해서 지도를 보여줄 때 필요한 과정이다.
Google Play service 라이브러리 사용 설정하기
- 구글맵 서비스 v2는 Play services 라이브러리를 사용한다. 따라서 구글 맵을
사용하려면 이 라이브러리를 추가해야 한다.
XML 레이아웃에 맵프래그먼트 추가하기
- 앱 화면에 지도를 넣으려면 XML 레이아웃에 맵프래그먼트를 추가한다.
소스 코드에서 내 위치로 지도 이동시키기
- 지도를 띄울 때 내 위치가 보여야 하므로 소스 코드에 지도를 내 위치에 맞추어
기능을 추가한다.
매니페스트에 설정 추가하기’
- 지도를 사용하려면 권한이 필요하다. 이 외에도 필요한 설정 정보를 매니페스트에 등록해야 한다.
지도 API 키
- 구글맵 서비스를 사용하려면 구글 콘솔에서 지도 API 키를 발급 받아 앱의 매니페스트에 넣어주어야 한다.
Google Play services 라이브러리 사용 설정하기
예제
MainActivity.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
package org.techtown.location;
import android.content.Context;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.MapsInitializer;
import com.google.android.gms.maps.OnMapReadyCallback;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.BitmapDescriptorFactory;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.MarkerOptions;
import com.yanzhenjie.permission.Action;
import com.yanzhenjie.permission.AndPermission;
import com.yanzhenjie.permission.runtime.Permission;
import java.util.List;
public class MainActivity extends AppCompatActivity {
SupportMapFragment mapFragment;
GoogleMap map;
MarkerOptions myLocationMarker;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mapFragment = (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map);
mapFragment.getMapAsync(new OnMapReadyCallback() {
@Override
public void onMapReady(GoogleMap googleMap) {
Log.d("Map", "지도 준비됨.");
map = googleMap;
}
});
try {
MapsInitializer.initialize(this);
} catch (Exception e) {
e.printStackTrace();
}
Button button = findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startLocationService();
}
});
AndPermission.with(this)
.runtime()
.permission(
Permission.ACCESS_FINE_LOCATION,
Permission.ACCESS_COARSE_LOCATION)
.onGranted(new Action<List<String>>() {
@Override
public void onAction(List<String> permissions) {
showToast("허용된 권한 갯수 : " + permissions.size());
}
})
.onDenied(new Action<List<String>>() {
@Override
public void onAction(List<String> permissions) {
showToast("거부된 권한 갯수 : " + permissions.size());
}
})
.start();
}
public void showToast(String message) {
Toast.makeText(this, message, Toast.LENGTH_LONG).show();
}
public void startLocationService() {
LocationManager manager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
try {
Location location = manager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
if (location != null) {
double latitude = location.getLatitude();
double longitude = location.getLongitude();
String message = "최근 위치 -> Latitude : " + latitude + "\nLongitude:" + longitude;
Log.d("Map", message);
}
GPSListener gpsListener = new GPSListener();
long minTime = 10000;
float minDistance = 0;
manager.requestLocationUpdates(
LocationManager.GPS_PROVIDER,
minTime, minDistance, gpsListener);
Toast.makeText(getApplicationContext(), "내 위치확인 요청함",
Toast.LENGTH_SHORT).show();
} catch(SecurityException e) {
e.printStackTrace();
}
}
class GPSListener implements LocationListener {
public void onLocationChanged(Location location) {
Double latitude = location.getLatitude();
Double longitude = location.getLongitude();
String message = "내 위치 -> Latitude : "+ latitude + "\nLongitude:"+ longitude;
Log.d("Map", message);
showCurrentLocation(latitude, longitude);
}
public void onProviderDisabled(String provider) { }
public void onProviderEnabled(String provider) { }
public void onStatusChanged(String provider, int status, Bundle extras) { }
}
private void showCurrentLocation(Double latitude, Double longitude) {
LatLng curPoint = new LatLng(latitude, longitude);
map.animateCamera(CameraUpdateFactory.newLatLngZoom(curPoint, 15));
showMyLocationMarker(curPoint);
}
private void showMyLocationMarker(LatLng curPoint) {
if (myLocationMarker == null) {
myLocationMarker = new MarkerOptions();
myLocationMarker.position(curPoint);
myLocationMarker.title("● 내 위치\n");
myLocationMarker.snippet("● GPS로 확인한 위치");
myLocationMarker.icon(BitmapDescriptorFactory.fromResource(R.drawable.mylocation));
map.addMarker(myLocationMarker);
} else {
myLocationMarker.position(curPoint);
}
}
}
animateCamera
메서드는 지도의 축적 (Scale)을 지정할 수 있다.
축적 값이 클수록 가까이서 본 것처럼 확대되는데 18 정도의 값은 도시 지역의 경우 건물 몇 개를 한눈에 볼 수 있을 정도로 확대하여 보여준다.
AndroidManifet.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.techtown.location">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<application
android:usesCleartextTraffic="true"
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/Theme.SampleLocationMap">
<meta-data android:name="com.google.android.geo.API_KEY"
android:value="Input Your API Key"/>
<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>
buld.gradle(Module:name)
1
2
3
4
5
6
7
8
9
10
11
12
13
dependencies {
implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'com.google.android.material:material:1.3.0'
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
implementation 'com.google.android.gms:play-services-maps:17.0.0'
testImplementation 'junit:junit:4.+'
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
implementation 'com.yanzhenjie:permission:2.0.3'
}