현재 위치와 지도 보여주기
activity_main.mxl
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<Button
android:id="@+id/button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="내 위치 요청하기" />
<fragment
android:id="@+id/map"
android:layout_width="match_parent"
android:layout_height="match_parent"
class="com.google.android.gms.maps.SupportMapFragment" />
</LinearLayout>
activity_main.xml파일을 열고 최상위 레이아웃을 LinearLayout으로 변경하고 orientation 속성값은 vertical로 설정합니다. LinearLayout안에 '내 위치 요청하기'글자가 표시된 버튼 하나와 프래그먼트를 추가합니다. 디자인 화면에서 Button과 View를 추가하고 위치를 잡은 후 오른쪽 위에 있는 [Code] 아이콘을 눌러 원본 XML 코드를 표시합니다. 그리고 프래그먼트는 뷰처럼 화면에서 일정 영역을 할당받게 되며 <fragment> 태그를 사용합니다. 프래그먼트에서 할당받은 화면 영역에 보이는 것은 class 속성으로 지정된 클래스지만 여기에서는 SupportMapFragment라는 이름의 클래스가 사용됩니다. id속성 값은 map으로 설정하여 소스 코드에서 프래그먼트를 찾을 수 있도록 합니다
MainActivity.java
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);
}
}
}
지도를 보여주기 위해 XML 레이아웃에 추가한 프래그먼트에는 class속성으로 SupportMapFragment라는 이름의 클래스가 할당되어 있습니다.SupportMapFragment안에 들어있는 GoogleMap객체 위에 지도가 표시됩니다 GoogleMap객체는 프래그먼트가 초기화된 후에 참조할 수 있는데, 레이아웃에 정의한 MapFragment객체를 소스 코드에서 참조한 후 getMapAsync메서드를 호출하면 GoogleMap객체를 참조할 수 있습니다. getMapAsync메서드는 내부적으로 지도를 다루는 GoogleMap메서드를 호출하면 GoogleMap 객체를 참조할 수 있습니다. getMapAsync메서드는 내부적으로 지도를 다루는 GoogleMap객체를 초기화하는데 비동기 방식으로 처리됩니다. 콜백 객체를 파라미터로 전달한 후 초기화가 완료될 때 콜백 객체 안의 함수가 자동으로 호출되도록 만듭니다. SupportMapFragment객체를 참조한 후 getMapAsync메서드를 호출했습니다 메서드는 바동기 방식으로 동작하기 때문에 지도가 사용가능하게 된 후에 onMapReady메서드가 자동으로 호출됩니다. 지도가 준비되었다면 [내 위치 요청하기] 버튼을 눌렀을 때 sartLocationService메서드를 호출해야 합니다. sartLocationService 메서드는 예제와 동일하게 위치 관리자로부터 현재 위치를 전달받도록 구현하면 됩니다. 내부 클래스인 GPSListener도 동일하게 작성합니다 이때 위치 리스너(GPSListener)의 onLocationChanged메서드 안에 다음과 같은 코드를 추가합니다 showCurrentLocation 메서드로 전달된 위도와 경도의 값은 LatLng 객체로 만들면 지도 위에 표시할 수 있습니다. LatLag객체는 경위도 좌표로 구성된 위치를 지도에 표시할 수 있도록 정의된 객체입니다. Changed메서드가 호출되는데 updateCoordinates메서드를 호출한 후 서비스를 종료합니다. 서비스를 종료하는 이유는 앱 위젯의 업데이트 주기때마다 한 번씩만 위치 정보를 확인하고 종료합니다