[Android] 안드로이드 Fragment에서 현재 위치(위도, 경도) 가져오기
모바일앱에 현재 위치 날씨 정보 기능을 구현하던 중 메인 Fragment에서 현재 위치(위도, 경도)를 가져와야 할 일이 생겼다.
위도 경도 가져오는 방법에 대해서는 아직 모르는 부분이 많아 아래 블로그를 참고했다.
https://gwynn.tistory.com/4
GpsTracker.java
먼저 GpsTraker 코드부터 보겠다.
package com.example.pethealth;
import android.Manifest;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;
import androidx.core.content.ContextCompat;
public class GpsTracker extends Service implements LocationListener {
private final Context mContext;
Location location;
double latitude;
double longitude;
private static final long MIN_DISTANCE_CHANGE_FOR_UPDATES = 10;
private static final long MIN_TIME_BW_UPDATES = 1000 * 60 * 1;
protected LocationManager locationManager;
public GpsTracker(Context context) {
this.mContext = context;
getLocation();
}
public Location getLocation() {
try {
locationManager = (LocationManager) mContext.getSystemService(LOCATION_SERVICE);
boolean isGPSEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
boolean isNetworkEnabled = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
if (!isGPSEnabled && !isNetworkEnabled) {
} else {
int hasFineLocationPermission = ContextCompat.checkSelfPermission(mContext,
Manifest.permission.ACCESS_FINE_LOCATION);
int hasCoarseLocationPermission = ContextCompat.checkSelfPermission(mContext,
Manifest.permission.ACCESS_COARSE_LOCATION);
if (hasFineLocationPermission == PackageManager.PERMISSION_GRANTED &&
hasCoarseLocationPermission == PackageManager.PERMISSION_GRANTED) {
;
} else
return null;
if (isNetworkEnabled) {
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, MIN_TIME_BW_UPDATES, MIN_DISTANCE_CHANGE_FOR_UPDATES, this);
if (locationManager != null)
{
location = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
if (location != null)
{
latitude = location.getLatitude();
longitude = location.getLongitude();
}
}
}
if (isGPSEnabled)
{
if (location == null)
{
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, MIN_TIME_BW_UPDATES, MIN_DISTANCE_CHANGE_FOR_UPDATES, this);
if (locationManager != null)
{
location = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
if (location != null)
{
latitude = location.getLatitude();
longitude = location.getLongitude();
}
}
}
}
}
}
catch (Exception e)
{
Log.d("@@@", ""+e.toString());
}
return location;
}
public double getLatitude()
{
if(location != null)
{
latitude = location.getLatitude();
}
return latitude;
}
public double getLongitude()
{
if(location != null)
{
longitude = location.getLongitude();
}
return longitude;
}
@Override
public void onLocationChanged(Location location)
{
}
@Override
public void onProviderDisabled(String provider)
{
}
@Override
public void onProviderEnabled(String provider)
{
}
@Override
public void onStatusChanged(String provider, int status, Bundle extras)
{
}
@Override
public IBinder onBind(Intent arg0)
{
return null;
}
public void stopUsingGPS()
{
if(locationManager != null)
{
locationManager.removeUpdates(GpsTracker.this);
}
}
}
위 코드를 간단하게 설명하자면
- 먼저 GpsTraker 객체가 생성되고 getLocation 메서드를 실행한다.
- getLocation 메서드가 실행되면 locationManager를 통해서 GPS와 네트워크가 사용가능한지 체크한다.(isGPSEnabled, isNetworkEnabled)
- 만약 GPS와 네트워크가 사용가능하다면 (else 부분) 위치에 접근할 수 있는 권한(hasFineLocationPermission, hasCoarseLocationPermission)을 획득한다.
- GPS와 네트워크 중 무엇이 사용가능한지 체크하고 권한에 맞게 locationManager를 사용하여 위치를 가져온다. getLatitude와 getLongitude 메서드를 통해 위도와 경도를 얻을 수 있다.
HomeFragment
그 다음은 메인 Fragment 부분이다.
public class HomeFragment extends Fragment {
private static final int GPS_ENABLE_REQUEST_CODE = 2001;
private static final int PERMISSIONS_REQUEST_CODE = 100;
String[] REQUIRED_PERMISSIONS = {Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION};
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_home, container, false);
if (checkLocationServicesStatus()) {
checkRunTimePermission();
} else {
showDialogForLocationServiceSetting();
}
GpsTracker gpsTracker = new GpsTracker(getContext());
double latitude = gpsTracker.getLatitude();
double longitude = gpsTracker.getLongitude();
}
@Override
public void onRequestPermissionsResult(int permsRequestCode,
@NonNull String[] permissions,
@NonNull int[] grandResults) {
if (permsRequestCode == PERMISSIONS_REQUEST_CODE && grandResults.length == REQUIRED_PERMISSIONS.length) {
// 요청 코드가 PERMISSIONS_REQUEST_CODE 이고, 요청한 퍼미션 개수만큼 수신되었다면
boolean check_result = true;
// 모든 퍼미션을 허용했는지 체크합니다.
for (int result : grandResults) {
if (result != PackageManager.PERMISSION_GRANTED) {
check_result = false;
break;
}
}
if (check_result) {
//위치 값을 가져올 수 있음
;
} else {
// 거부한 퍼미션이 있다면 앱을 사용할 수 없는 이유를 설명해주고 앱을 종료합니다.2 가지 경우가 있습니다.
if (ActivityCompat.shouldShowRequestPermissionRationale(getActivity(), REQUIRED_PERMISSIONS[0])
|| ActivityCompat.shouldShowRequestPermissionRationale(getActivity(), REQUIRED_PERMISSIONS[1])) {
Toast.makeText(getContext(), "퍼미션이 거부되었습니다. 앱을 다시 실행하여 퍼미션을 허용해주세요.", Toast.LENGTH_LONG).show();
getActivity().finish();
} else {
Toast.makeText(getContext(), "퍼미션이 거부되었습니다. 설정(앱 정보)에서 퍼미션을 허용해야 합니다. ", Toast.LENGTH_LONG).show();
}
}
}
}
void checkRunTimePermission() {
//런타임 퍼미션 처리
// 1. 위치 퍼미션을 가지고 있는지 체크합니다.
int hasFineLocationPermission = ContextCompat.checkSelfPermission(getContext(),
Manifest.permission.ACCESS_FINE_LOCATION);
int hasCoarseLocationPermission = ContextCompat.checkSelfPermission(getContext(),
Manifest.permission.ACCESS_COARSE_LOCATION);
if (hasFineLocationPermission == PackageManager.PERMISSION_GRANTED &&
hasCoarseLocationPermission == PackageManager.PERMISSION_GRANTED) {
// 2. 이미 퍼미션을 가지고 있다면
// ( 안드로이드 6.0 이하 버전은 런타임 퍼미션이 필요없기 때문에 이미 허용된 걸로 인식합니다.)
// 3. 위치 값을 가져올 수 있음
} else { //2. 퍼미션 요청을 허용한 적이 없다면 퍼미션 요청이 필요합니다. 2가지 경우(3-1, 4-1)가 있습니다.
// 3-1. 사용자가 퍼미션 거부를 한 적이 있는 경우에는
if (ActivityCompat.shouldShowRequestPermissionRationale(getActivity(), REQUIRED_PERMISSIONS[0])) {
// 3-2. 요청을 진행하기 전에 사용자가에게 퍼미션이 필요한 이유를 설명해줄 필요가 있습니다.
Toast.makeText(getActivity(), "이 앱을 실행하려면 위치 접근 권한이 필요합니다.", Toast.LENGTH_LONG).show();
// 3-3. 사용자게에 퍼미션 요청을 합니다. 요청 결과는 onRequestPermissionResult에서 수신됩니다.
ActivityCompat.requestPermissions(getActivity(), REQUIRED_PERMISSIONS,
PERMISSIONS_REQUEST_CODE);
} else {
// 4-1. 사용자가 퍼미션 거부를 한 적이 없는 경우에는 퍼미션 요청을 바로 합니다.
// 요청 결과는 onRequestPermissionResult에서 수신됩니다.
ActivityCompat.requestPermissions(getActivity(), REQUIRED_PERMISSIONS,
PERMISSIONS_REQUEST_CODE);
}
}
}
//여기부터는 GPS 활성화를 위한 메소드들
private void showDialogForLocationServiceSetting() {
AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
builder.setTitle("위치 서비스 비활성화");
builder.setMessage("앱을 사용하기 위해서는 위치 서비스가 필요합니다.\n"
+ "위치 설정을 수정하실래요?");
builder.setCancelable(true);
builder.setPositiveButton("설정", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int id) {
Intent callGPSSettingIntent
= new Intent(android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS);
startActivityForResult(callGPSSettingIntent, GPS_ENABLE_REQUEST_CODE);
}
});
builder.setNegativeButton("취소", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int id) {
dialog.cancel();
}
});
builder.create().show();
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode) {
case GPS_ENABLE_REQUEST_CODE:
//사용자가 GPS 활성 시켰는지 검사
if (checkLocationServicesStatus()) {
if (checkLocationServicesStatus()) {
Log.d("@@@", "onActivityResult : GPS 활성화 되있음");
checkRunTimePermission();
return;
}
}
break;
}
}
public boolean checkLocationServicesStatus() {
LocationManager locationManager = (LocationManager) getActivity().getSystemService(LOCATION_SERVICE);
return locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)
|| locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
}
전체적으로 수행하는 순서를 보면
-
액티비티가 실행되면 checkLocationServicesStatus 메소드를 실행한다.
-
locationManager 객체를 사용하여 권한에 접근할 수 있는지 여부를 확인한다.
-
만약 권한에 접근할 수 있다면 checkRunTimePermission 메소드를 실행하고 접근할 수 없다면 showDialogForLocationServiceSetting를 수행한다.
-
그 후 gpsTracker 객체를 생성하고 getLatitude와 getLongitude 메소드를 사용하여 latitude와 longitude에 위도와 경도의 값을 받아온다.
-
checkRunTimePermission 메소드는 위치 퍼미션을 가지고 있지 않으면 퍼미션 요청을 하는 메소드이고
showDialogForLocationServiceSetting 메소드는 권한을 설정해주기 위한 다이얼로그창을 띄워주는 메소드이다.
기존 코드에서 Activity에 쓰였던 코드를 Fragment에서 쓰일 수 있도록 변형하였고 버튼을 누르면 경도와 위도를 받아오는 것이 아닌 Fragment가 시작되자마자 위도와 경도를 받아올 수 있도록 수정하였다.
이처럼 현재 위치를 알기 위해 위도와 경도를 Fragment에서 받아오도록 해보았다.
위도와 경도를 통해 현재 위치의 이름을 알아오고 그 이름을 통해 날씨까지 받아오는 것도 곧 포스팅하도록 하겠다.