예전에 초창기 GPS 관련 자료를 얻기 위해 세미나를 찾아 다니고 자료를 수집할 때
우리나라에는 위성이 없으니 얻어 써야 하고 GPS 정보 자체가 군용으로 사용되고 있어서
일부러 오차를 약 20m 정도 나도록 신호를 주고 있다고 했었습니다.
그래서 그 20m를 보정하는 것 자체가 큰 기술이라고 했는데 이제는 핸드폰에서 아무때나
꺼내서 사용할 수 있게 되었으니 참 신기한 일입니다.
물론 그동안 수많은 지도 업체와 네비 업체가 문을 닫았지요.
1. 좌표값 생성
위치정보를 구하는 방법은 2가지가 있습니다.
1.1 GPS Provider
3각 측량의 방법으로 좌표를 위성을 이용하여 취득합니다.
그러므로 위성의 전파를 잡지 못하는 실내에서는 사용이 어렵고 실외에서는 건물 또는
계곡이 깊으면 전파를 잡기 어려워 위치를 잡지 못할 수 있습니다.
1.2 Network Provider
이동통신 기지국 또는 WiFi access point들을 이용하여 측정을 할 수 있습니다.
1.3 Passive Provider
위치를 구하는 방법이 2가지라고 했는데 Passive 방식은 좌표를 직접 구하는 것이 아니고
다른 어플리케이션이나 서비스가 좌표 값을 구하면 단순히 그 값을 받아 오기만 하는
전달자 역할을 하기 때문에 값을 얻을 수는 있지만 구한다고는 할 수 없습니다.
2. LocationManager 개요
2.1 Permission
모바일 기기의 장치를 사용하려면 사용 허가가 필요합니다.
각 provider 별 사용 허가에 대한 변수들 입니다.
대부분 ACCESS_FINE_LOCATION 이거 하나면 권한을 받을 수 있습니다.
Provider |
permission |
GPS |
android.permission.ACCESS_FINE_LOCATION |
Network |
android.permission.ACCESS_COARSE_LOCATION 또는 android.permission.ACCESS_FINE_LOCATION |
Passive |
android.permission.ACCESS_FINE_LOCATION |
2.2 Provider
Type |
Parameter |
설명 |
String |
GPS_PROVIDER |
GPS를 이용 위치 제공 |
String |
NETWORK_PROVIDER |
기지국, WiFi를 이용 위치 제공 |
String |
TYPE_STEP_COUNTER |
기존 좌표값 이용 위치 제공 |
2.3 Method
Type |
Method / 설명 |
List |
getAllProviders() - 모든 Provider 정보를 리턴 한다. |
LocationProvider |
getProvider(String name) - 명칭(name)에 대한 Provider 정보를 리턴 한다. |
List |
getProviders(boolean enabledOnly) - true를 입력하면 현재 사용 가능한 Provider의 목록을 리턴 합니다. - false를 입력하면 비활성화 포함 모든 Provider의 목록을 리턴 합니다. |
boolean |
isProviderEnabled(String provider) - 입력한 Provider의 명칭에 대한 사용 가능 여부를 리턴 합니다. |
void |
removeUpdates(LocationListener listener) - 더 이상 위치 정보가 필요 없을 때 위치 정보 수집을 종료 시킵니다. |
void |
requestLocationUpdates(String provider, long minTime, float minDistance, LocationListener listener) - Provider를 등록하고 기입한 거리와 시간의 변동이 있을 때 마다 update 된 위치 정보를 리턴 합니다. |
3. Location 프로그램
그럼 좌표 값을 얻기가 얼마나 쉬운지 한번 알아보도록 하겠습니다.
3.1 신규 프로젝트 생성
프로젝트 명을 적당하게 명명해서 생성 하고 기타 설정 사항도 본인의 기호에 맞게 설정 하여 신규 프로젝트를 하나 생성 합니다.
저는 항상 Device는 Android 4.0을 선택 하고
Activity는 Empty로 설정 합니다.
3.2 Permission
장치 사용에 대한 권한 허가는 두개 다 적어 줍니다.
AndroidManifest.xml
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
3.3 Layout 작성
지금까지 Layout은 그냥 TextView를 죽 나열하는 방식으로 작업 했는데
이번에는 기입 하는게 많고 우측 정렬도 필요해서 GridLayout을 사용했습니다.
<GridLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:columnCount="2" app:layout_constraintTop_toBottomOf="@+id/tvTitle" >
참고로 여기서는 그냥 android:columnCount=”2” 이것만 보시면 됩니다.
컬럼이 2개 이니까 아래에 나열된 TextView들은 자동으로 2개씩 나누어져서 하나의 Row를 만듭니다.
HTML의 Table tag보다 참 편하죠.
3.4 MainActivity.java
- 권한 설정
이미 Manifest에 권한을 추가 했지만 Android 6.0 부터는 source 안에도 권한에 대한 체크를 해야 한다는군요.
저는 location를 사용하는 모든 곳에 추가를 했습니다.
안그러면 실행은 되는데 빨간 줄이 자꾸 나와서 눈에 거슬리더군요if (ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { //권한이 없을 경우 최초 권한 요청 또는 사용자에 의한 재요청 확인 if (ActivityCompat.shouldShowRequestPermissionRationale(this, android.Manifest.permission.ACCESS_FINE_LOCATION) && ActivityCompat.shouldShowRequestPermissionRationale(this, android.Manifest.permission.ACCESS_COARSE_LOCATION)) { // 권한 재요청 ActivityCompat.requestPermissions(this, new String[]{android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.ACCESS_COARSE_LOCATION}, 100); return; } else { ActivityCompat.requestPermissions(this, new String[]{android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.ACCESS_COARSE_LOCATION}, 100); return; } }
- 초기 좌표값
프로그램이 시작되면 우선 초기 좌표 값을 기록하도록 했습니다.
Location lastKnownLocation = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER); if (lastKnownLocation != null) { double lng = lastKnownLocation.getLongitude(); double lat = lastKnownLocation.getLatitude(); Log.d(TAG, "longtitude=" + lng + ", latitude=" + lat); tvGpsLatitude.setText(":: " + Double.toString(lat )); tvGpsLongitude.setText((":: " + Double.toString(lng))); }
그리고 초기 값을 나타낼 때만 중간에 콜론을 두개 찍었는데( :: ) 이러면 초기값이 그대로 인지
아니면 변경된 값을 얻어오는지 확인을 할 수 있습니다.
- Provider 작동 확인
기기에 어떤 Provider들이 있는지 값을 가져오고
listProviders = locationManager.getAllProviders();
각 Provider별 작동 여부를 확인 하여 Update가 되도록 합니다.
requestLocationUpdates()의 두번 째 값은 갱신 시간이고 세번 째 값은 갱신 이동 거리입니다.
저는 둘다 0으로 해서 계속 값을 갱신 하도록 했습니다.
이렇게요.
if(listProviders.get(i).equals(LocationManager.GPS_PROVIDER)) { isEnable[0] = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER); tvGpsEnable.setText(": " + String.valueOf(isEnable[0])); locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, this); }
- LocationChange
onLocationChanged(Location location)에서 이동을 하면 좌표 값이 변경되고 변경된 좌표를 얻어옵니다.
if(location.getProvider().equals(LocationManager.GPS_PROVIDER)) { latitude = location.getLatitude(); longitude = location.getLongitude(); tvGpsLatitude.setText(": " + Double.toString(latitude )); tvGpsLongitude.setText((": " + Double.toString(longitude))); Log.d(TAG + " GPS : ", Double.toString(latitude )+ '/' + Double.toString(longitude)); }
- 수집 중단
어플리케이션을 사용하지 않을 때는 더 이상 좌표 수집을 하지 않도록 중단해야 합니다.
안그러면 계속 백그라운드에서 작업을 하여 리소스를 잡아먹겠죠.
locationManager.removeUpdates(this);
4. 결과
4.1 결과 화면
GPS는 잘 잡히는데 Network은 안잡히는 걸로 나오네요.
구해진 좌표 값은 google map과 연동하면 바로 위치를 확인 할 수 있습니다.
실제로 google map과 연동 테스트를 하려면 구글에 회원 가입을 하고
맵을 사용하겠다고 해서 API 키값을 받아야 합니다.
귀찮으니 그냥 간단하게 구글 맵에서 위치를 확인 할 수 있는데요.
구글 지도를 웹으로 열면 주소창의 URL에 좌표가 같이 나타 납니다.
그럼 거기에 핸드폰으로 구한 좌표를 콤마로 구분해서 변경해 주면 위치를 확인할 수 있습니다.
https://www.google.com/maps/@37.5555062,126.7976293,14z
4.2 Source Code
4.3 APK File
5. Full Source Code
원래 취지대로 그냥 복사해서 붙여넣기를 해서 사용할 때를 위해 전체 소스를 남김니다
5.1 AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.desk.locprovider"> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/> <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"> <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"> <TextView android:id="@+id/tvTitle" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Android Location Test" android:layout_marginTop="20dp" android:textSize="30dp" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" /> <GridLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:columnCount="2" app:layout_constraintTop_toBottomOf="@+id/tvTitle" > <TextView android:id="@+id/tvGpsEnableLabel" android:layout_gravity="right" android:text="GPS Enable " android:textSize="20dp" /> <TextView android:id="@+id/tvGpsEnable" android:text="" android:textSize="20dp" /> <TextView android:id="@+id/tvNetworkEnableLabel" android:layout_gravity="right" android:text="Network Enable " android:textSize="20dp" /> <TextView android:id="@+id/tvNetworkEnable" android:text="" android:textSize="20dp" /> <TextView android:id="@+id/tvPassiveEnableLabel" android:layout_gravity="right" android:text="Passive Enable " android:textSize="20dp" /> <TextView android:id="@+id/tvPassiveEnable" android:text="" android:textSize="20dp" /> <TextView android:id="@+id/tvGpsLocationLabel" android:layout_gravity="right" android:text="GPS Location " android:textSize="20dp" /> <TextView android:id="@+id/tvGpsLocation" android:text="" android:textSize="20dp" /> <TextView android:id="@+id/tvGpsLatitudeLabel" android:layout_gravity="right" android:text="GPS Latitude " android:textSize="20dp" /> <TextView android:id="@+id/tvGpsLatitude" android:text="" android:textSize="20dp" /> <TextView android:id="@+id/tvGpsLongitudeLabel" android:layout_gravity="right" android:text="GPS Longitude " android:textSize="20dp" /> <TextView android:id="@+id/tvGpsLongitude" android:text="" android:textSize="20dp" /> <TextView android:id="@+id/tvNetworkLocationLabel" android:layout_gravity="right" android:text="Network Location " android:textSize="20dp" /> <TextView android:id="@+id/tvNetworkLocation" android:text="" android:textSize="20dp" /> <TextView android:id="@+id/tvNetworkLatitudeLabel" android:layout_gravity="right" android:text="Network Latitude " android:textSize="20dp" /> <TextView android:id="@+id/tvNetworkLatitude" android:text="" android:textSize="20dp" /> <TextView android:id="@+id/tvNetworkLongitudeLabel" android:layout_gravity="right" android:text="Network Longitude " android:textSize="20dp" /> <TextView android:id="@+id/tvNetworkLongitude" android:text="" android:textSize="20dp" /> <TextView android:id="@+id/tvPassiveLocationLabel" android:layout_gravity="right" android:text="Passive Location " android:textSize="20dp" /> <TextView android:id="@+id/tvPassiveLocation" android:text="" android:textSize="20dp" /> <TextView android:id="@+id/tvPassiveLatitudeLabel" android:layout_gravity="right" android:text="Passive Latitude " android:textSize="20dp" /> <TextView android:id="@+id/tvPassiveLatitude" android:text="" android:textSize="20dp" /> <TextView android:id="@+id/tvPassivekLongitudeLabel" android:layout_gravity="right" android:text="Passive Longitude " android:textSize="20dp" /> <TextView android:id="@+id/tvPassivekLongitude" android:text="" android:textSize="20dp" /> </GridLayout> </android.support.constraint.ConstraintLayout>
5.3 MainAcitvity.java
package com.example.desk.locprovider; import android.content.Context; import android.content.pm.PackageManager; import android.location.Location; import android.location.LocationListener; import android.location.LocationManager; import android.support.v4.app.ActivityCompat; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import android.widget.TextView; import java.util.List; public class MainActivity extends AppCompatActivity implements LocationListener { private LocationManager locationManager; private List<String> listProviders; private TextView tvGpsEnable, tvNetworkEnable, tvPassiveEnable, tvGpsLatitude, tvGpsLongitude; private TextView tvNetworkLatitude, tvNetworkLongitude, tvPassiveLatitude, tvPassivekLongitude; private String TAG = "LocationProvider"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); tvGpsEnable = (TextView)findViewById(R.id.tvGpsEnable); tvNetworkEnable = (TextView)findViewById(R.id.tvNetworkEnable); tvPassiveEnable = (TextView)findViewById(R.id.tvPassiveEnable); tvGpsLatitude = (TextView)findViewById(R.id.tvGpsLatitude); tvGpsLongitude = (TextView)findViewById(R.id.tvGpsLongitude); tvNetworkLatitude = (TextView)findViewById(R.id.tvNetworkLatitude); tvNetworkLongitude = (TextView)findViewById(R.id.tvNetworkLongitude); tvPassiveLatitude = (TextView)findViewById(R.id.tvPassiveLatitude); tvPassivekLongitude = (TextView)findViewById(R.id.tvPassivekLongitude); //권한 체크 if (ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) { return; } locationManager = (LocationManager)getSystemService(Context.LOCATION_SERVICE); Location lastKnownLocation = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER); if (lastKnownLocation != null) { double lng = lastKnownLocation.getLongitude(); double lat = lastKnownLocation.getLatitude(); Log.d(TAG, "longtitude=" + lng + ", latitude=" + lat); tvGpsLatitude.setText(":: " + Double.toString(lat )); tvGpsLongitude.setText((":: " + Double.toString(lng))); } lastKnownLocation = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER); if (lastKnownLocation != null) { double lng = lastKnownLocation.getLongitude(); double lat = lastKnownLocation.getLatitude(); Log.d(TAG, "longtitude=" + lng + ", latitude=" + lat); tvNetworkLatitude.setText(":: " + Double.toString(lat )); tvNetworkLongitude.setText((":: " + Double.toString(lng))); } lastKnownLocation = locationManager.getLastKnownLocation(LocationManager.PASSIVE_PROVIDER); if (lastKnownLocation != null) { double lng = lastKnownLocation.getLongitude(); double lat = lastKnownLocation.getLatitude(); Log.d(TAG, "longtitude=" + lng + ", latitude=" + lat); tvPassiveLatitude.setText(":: " + Double.toString(lat )); tvPassivekLongitude.setText((":: " + Double.toString(lng))); } listProviders = locationManager.getAllProviders(); boolean [] isEnable = new boolean[3]; for(int i=0; i<listProviders.size();i++) { if(listProviders.get(i).equals(LocationManager.GPS_PROVIDER)) { isEnable[0] = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER); tvGpsEnable.setText(": " + String.valueOf(isEnable[0])); locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, this); } else if(listProviders.get(i).equals(LocationManager.NETWORK_PROVIDER)) { isEnable[1] = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER); tvNetworkEnable.setText(": " + String.valueOf(isEnable[1])); locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, this); } else if(listProviders.get(i).equals(LocationManager.PASSIVE_PROVIDER)) { isEnable[2] = locationManager.isProviderEnabled(LocationManager.PASSIVE_PROVIDER); tvPassiveEnable.setText(": " + String.valueOf(isEnable[2])); locationManager.requestLocationUpdates(LocationManager.PASSIVE_PROVIDER, 0, 0, this); } } Log.d(TAG, listProviders.get(0) + '/' + String.valueOf(isEnable[0])); Log.d(TAG, listProviders.get(1) + '/' + String.valueOf(isEnable[1])); Log.d(TAG, listProviders.get(2) + '/' + String.valueOf(isEnable[2])); } @Override public void onProviderEnabled(String provider) { if (ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) { return; } locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, this); locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, this); locationManager.requestLocationUpdates(LocationManager.PASSIVE_PROVIDER, 0, 0, this); } @Override public void onLocationChanged(Location location) { double latitude = 0.0; double longitude = 0.0; if(location.getProvider().equals(LocationManager.GPS_PROVIDER)) { latitude = location.getLatitude(); longitude = location.getLongitude(); tvGpsLatitude.setText(": " + Double.toString(latitude )); tvGpsLongitude.setText((": " + Double.toString(longitude))); Log.d(TAG + " GPS : ", Double.toString(latitude )+ '/' + Double.toString(longitude)); } if(location.getProvider().equals(LocationManager.NETWORK_PROVIDER)) { latitude = location.getLatitude(); longitude = location.getLongitude(); tvNetworkLatitude.setText(": " + Double.toString(latitude )); tvNetworkLongitude.setText((": " + Double.toString(longitude))); Log.d(TAG + " NETWORK : ", Double.toString(latitude )+ '/' + Double.toString(longitude)); } if(location.getProvider().equals(LocationManager.PASSIVE_PROVIDER)) { latitude = location.getLatitude(); longitude = location.getLongitude(); tvPassiveLatitude.setText(": " + Double.toString(latitude )); tvPassivekLongitude.setText((": " + Double.toString(longitude))); Log.d(TAG + " PASSIVE : ", Double.toString(latitude )+ '/' + Double.toString(longitude)); } } @Override public void onStatusChanged(String provider, int status, Bundle extras) { } @Override public void onProviderDisabled(String provider) { } @Override protected void onStart() { super.onStart(); if (ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { //권한이 없을 경우 최초 권한 요청 또는 사용자에 의한 재요청 확인 if (ActivityCompat.shouldShowRequestPermissionRationale(this, android.Manifest.permission.ACCESS_FINE_LOCATION) && ActivityCompat.shouldShowRequestPermissionRationale(this, android.Manifest.permission.ACCESS_COARSE_LOCATION)) { // 권한 재요청 ActivityCompat.requestPermissions(this, new String[]{android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.ACCESS_COARSE_LOCATION}, 100); return; } else { ActivityCompat.requestPermissions(this, new String[]{android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.ACCESS_COARSE_LOCATION}, 100); return; } } } @Override protected void onPause() { super.onPause(); locationManager.removeUpdates(this); } @Override protected void onResume() { super.onResume(); if (ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) { return; } locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, this); locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, this); locationManager.requestLocationUpdates(LocationManager.PASSIVE_PROVIDER, 0, 0, this); } }
- copy coding -
'Android' 카테고리의 다른 글
[안드로이드] google map 사용을 위한 API 키 생성(2018.11) (0) | 2018.12.02 |
---|---|
안드로이드 GPS를 이용한 속도 측정 (7) | 2018.11.21 |
안드로이드 진동 센서 테스트 (VIBRATOR_SERVICE) (0) | 2018.10.31 |
안드로이드 중력 센서 (TYPE_GRAVITY) (0) | 2018.10.13 |
안드로이드 가속도 센서 비교 (TYPE_ACCELEROMETER/TYPE_LINEAR_ACCELERATION) (2) | 2018.10.13 |