티스토리 뷰
안드로이드(Java)/프로젝트 - ChatBot(챗봇)
안드로이드 스튜디오 Android studio // 위치 정보 권한 에러 수정
Moon96 2022. 6. 27. 10:55이번 프로젝트를 진행하면서 쓰는 마지막 글일 것 같다.
저번에 구글 맵 API를 사용해서 복지 맵을 구현했는데 다음날 와서 테스트를 해보려고 하니
에러가 발생했다.
발생한 에러는 현재 자신의 위치를 받아오는 함수가 작동하지 않는지 자꾸 null 값이 나왔다..
또한 지도가 로딩됐을 때 함수를 구현했기 때문에 권한을 주지 않아도 일단 지도로 이동했는데 이 점도 수정하고자 했다.
먼저 현재 위치를 다시 받아오기 위해 자료를 찾아보다가
가장 내 상태와 비슷한 자료를 찾았다
package com.cookandroid.users;
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,
android.Manifest.permission.ACCESS_FINE_LOCATION);
int hasCoarseLocationPermission = ContextCompat.checkSelfPermission(mContext,
android.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);
}
}
}
먼저 자기 위치를 받아오기 위한 트래커라는 클래스를 하나 만들어 주었다.
기존에는 구글맵 자체에 있는 GPS를 사용했지만 코드를 아무리 바꿔도 에러가 발생하여 변경했다.
public class MapActivity extends AppCompatActivity implements OnMapReadyCallback {
private GoogleMap mMap;
private long backpressedTime = 0;
private GpsTracker gpsTracker;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_map);
// Obtain the SupportMapFragment and get notified when the map is ready to be used.
SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
.findFragmentById(R.id.map);
mapFragment.getMapAsync(this);
}
/**
* Manipulates the map once available.
* This callback is triggered when the map is ready to be used.
* This is where we can add markers or lines, add listeners or move the camera. In this case,
* we just add a marker near Sydney, Australia.
* <p>
* If Google Play services is not installed on the device, the user will be prompted to install
* it inside the SupportMapFragment. This method will only be triggered once the user has
* installed Google Play services and returned to the app.
*/
@Override
public void onMapReady(GoogleMap googleMap) {
mMap = googleMap;
// 구글에서 등록한 api와 엮어주기
// 시작위치를 서울 시청으로 변경
gpsTracker = new GpsTracker(MapActivity.this);
double latitude = gpsTracker.getLatitude();
double longitude = gpsTracker.getLongitude();
LatLng currnt = new LatLng(latitude, longitude);
googleMap.moveCamera(CameraUpdateFactory.newLatLng(currnt));
googleMap.animateCamera(CameraUpdateFactory.zoomTo(15));
MarkerOptions markerOptions = new MarkerOptions();
markerOptions.position(currnt);
markerOptions.title("내 위치");
markerOptions.snippet("내 위치");
googleMap.addMarker(markerOptions);
생성한 트래커에서 경도와 위도를 불러와 현재 자신의 위치에 마커를 찍고 지도가 로딩되면
카메라가 이동되게 구현했다.
@Override
public void onRequestPermissionsResult(int permsRequestCode,
@NonNull String[] permissions,
@NonNull int[] grandResults) {
super.onRequestPermissionsResult(permsRequestCode, permissions, 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(this, REQUIRED_PERMISSIONS[0])
|| ActivityCompat.shouldShowRequestPermissionRationale(this, REQUIRED_PERMISSIONS[1])) {
Toast.makeText(Main2Activity.this, "퍼미션이 거부되었습니다. 앱을 다시 실행하여 퍼미션을 허용해주세요.", Toast.LENGTH_LONG).show();
finish();
} else {
Toast.makeText(Main2Activity.this, "퍼미션이 거부되었습니다. 설정(앱 정보)에서 퍼미션을 허용해야 합니다. ", Toast.LENGTH_LONG).show();
}
}
}
}
void checkRunTimePermission() {
//런타임 퍼미션 처리
// 1. 위치 퍼미션을 가지고 있는지 체크합니다.
int hasFineLocationPermission = ContextCompat.checkSelfPermission(Main2Activity.this,
android.Manifest.permission.ACCESS_FINE_LOCATION);
int hasCoarseLocationPermission = ContextCompat.checkSelfPermission(Main2Activity.this,
android.Manifest.permission.ACCESS_COARSE_LOCATION);
if (hasFineLocationPermission == PackageManager.PERMISSION_GRANTED &&
hasCoarseLocationPermission == PackageManager.PERMISSION_GRANTED) {
// 2. 이미 퍼미션을 가지고 있다면
// ( 안드로이드 6.0 이하 버전은 런타임 퍼미션이 필요없기 때문에 이미 허용된 걸로 인식합니다.)
// 3. 위치 값을 가져올 수 있음
Intent intent = new Intent(Main2Activity.this, MapActivity.class);
startActivity(intent);
overridePendingTransition(R.anim.slide_in_right, R.anim.slide_out_left);
finish();
} else { //2. 퍼미션 요청을 허용한 적이 없다면 퍼미션 요청이 필요합니다. 2가지 경우(3-1, 4-1)가 있습니다.
// 3-1. 사용자가 퍼미션 거부를 한 적이 있는 경우에는
if (ActivityCompat.shouldShowRequestPermissionRationale(Main2Activity.this, REQUIRED_PERMISSIONS[0])) {
// 3-2. 요청을 진행하기 전에 사용자가에게 퍼미션이 필요한 이유를 설명해줄 필요가 있습니다.
Toast.makeText(Main2Activity.this, "이 앱을 실행하려면 위치 접근 권한이 필요합니다.", Toast.LENGTH_LONG).show();
// 3-3. 사용자게에 퍼미션 요청을 합니다. 요청 결과는 onRequestPermissionResult에서 수신됩니다.
ActivityCompat.requestPermissions(Main2Activity.this, REQUIRED_PERMISSIONS,
PERMISSIONS_REQUEST_CODE);
} else {
// 4-1. 사용자가 퍼미션 거부를 한 적이 없는 경우에는 퍼미션 요청을 바로 합니다.
// 요청 결과는 onRequestPermissionResult에서 수신됩니다.
ActivityCompat.requestPermissions(Main2Activity.this, REQUIRED_PERMISSIONS,
PERMISSIONS_REQUEST_CODE);
}
}
}
//여기부터는 GPS 활성화를 위한 메소드들
private void showDialogForLocationServiceSetting() {
AlertDialog.Builder builder = new AlertDialog.Builder(Main2Activity.this);
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
protected 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) getSystemService(LOCATION_SERVICE);
return locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)
|| locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
}
해당 코드들은 정보 제공 동의와 위치 권한 여부 확인을 위한 함수들이다.
if (checkLocationServicesStatus()) {
checkRunTimePermission();
} else {
showDialogForLocationServiceSetting();
}
지도 버튼을 눌렀을 때 해당 함수들이 작동하며 권한 동의를 했을때만
복지 맵이 작동되도록 구현했다.
'안드로이드(Java) > 프로젝트 - ChatBot(챗봇)' 카테고리의 다른 글
안드로이드 스튜디오 Android studio // 애플리케이션 시연 영상 (0) | 2022.06.27 |
---|---|
안드로이드 스튜디오 Android studio // 구글 맵 api를 활용해서 지도 띄우기 (0) | 2022.06.22 |
안드로이드 스튜디오 Android studio // recyclerView 키보드가 올라오면 자동 스크롤 구현 (0) | 2022.06.20 |
안드로이드 스튜디오 Android studio // Intent 화면전환시 효과 주기 (0) | 2022.06.16 |
안드로이드 스튜디오 Android studio // RecyclerView 리사이클러뷰 클릭 이벤트(Url로 웹사이트 이동) (0) | 2022.06.14 |
댓글