본문 바로가기
코딩일기/날씨앱 만들기 프로젝트

날씨 앱 만들기 : 안드로이드 GPS 정보 받아오기

by 욱파이어니어 2021. 9. 8.
728x90
반응형

날씨 앱을 만들기 위해선 필수적으로 필요한 GPS 정보를 받아와 보기로 했다.

 

일단 GPS 정보를 받아오기 위해선 아래와 같은 과정을 거친다.

 

1. Manifest파일에 권한 추가하기

2. LocationManager 객체 생성하기

3. 안드로이드 위치정보 권한 확인후 권한 요청하기

4. 위치정보 권한 요청에 의한 콜백 함수인 onRequestPermissionsResult() 만들기

5. 위치정보 update 되었을때 실행하는 onLocationChanged() 만들기

 

 

1번 과정부터 차근차근히 살펴보자.

 

1. Manifest파일에 권한 추가하기

 

일단 Manifest 파일에 들어가서 아래처럼 권한을 추가한다.

    <!-- 현재 위치값 받기 위해 필요한 permission -->
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

 

 

2. LocationManager 객체 생성하기

 

권한을 추가해줬다면 LocationManager를 사용할 Activity로 이동해서 해당 Activity에서 

LocationManager 객체를 생성해줘야 한다

 

나는 캡슐화를 통해서 만들것이기 때문에 해당 Class 내에서 먼저 LocationManager 변수를 만들어줬고

 

private LocationManager lm;

 

그 다음에 해당 Activity 내의 onCreate() 내에서 객체를 생성해주었다.

        //LocationManager 객체 생성
        lm = (LocationManager) getSystemService(Context.LOCATION_SERVICE);

 

 

3. 안드로이드 위치정보 권한 확인후 권한 요청하기

그럼 이제 해당 앱에서의 위치정보 권한이 있는지 확인한 다음에 없다면 권한 요청을 해줘야 한다.

 

해당 부분의 코드는 아래와 같다.

 

        //위치정보 권한 허용되어 있는지 아닌지를 확인하는 부분
        if(ActivityCompat.checkSelfPermission(SplashActivity.this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED){
            //위치정보 권한 허용되어 있지 않다면 실행하는 코드, 여기서 request에 대한 응답이 나오면 아래에 있는 onRequestPermissionsResult() 함수를 콜백하게 됨
            ActivityCompat.requestPermissions(SplashActivity.this,new String[]{ Manifest.permission.ACCESS_FINE_LOCATION},200); //위치정보 권한을 요청한다.

        }else {
            //위치정보 권한이 허용되어 있을때 실행하는 코드

        }

이렇게 되면 이제 앱을 키게 되면 아래와 같이 위치정보 권한 요청을 하게 된다.

 

 

 

 

4. 위치정보 권한 요청에 의한 콜백 함수인 onRequestPermissionsResult() 만들기

onRequestPermissionsResult() 은 우리가 3번 과정에서 권한 요청에 대한 결과를 받았을때

호출하게 되는 함수이다.

 

나는 결과요청을 받았을때 아래와 같은 결과를 내볼 예정이다.

 

 

위치정보 권한 허가 요청을 받았을때

- 위치정보 권한 허가 요청을 받았을때는 현재 위치정보를 찍고 날씨정보 API 호출하기

 

위치정보 권한 허가 요청을 못 받았을때

- 위치정보 허가를 못받았을시에는 현재 위치정보를 토대로 날씨정보를 받아오지 못한다고 

ToastMessage 출력후 기본 설정 위치로 날씨정보 API 호출하기

 

그것에 대한 코드는 아래와 같다.

 

    @Override
    public void onRequestPermissionsResult(int requestCode,String[] permissions,int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);

        if(requestCode == 200){ //permissionCode가 200이고
            if(grantResults[0] == 0){ // 그중 가장 첫번째 result가 0 즉 승인된경우 진입
                Toast.makeText(getApplicationContext(),"위치정보 승인됨",Toast.LENGTH_SHORT).show(); //위치정보 승인됐다고 알리고
                //위치정보 권한을 받았다면 진입
                if(ActivityCompat.checkSelfPermission(SplashActivity.this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED){
                    lm.requestLocationUpdates(LocationManager.GPS_PROVIDER,0,0,this); //위치정보를 update하는 함수
                }
                getWeather(mavm);
            }else{ //위치정보를 허가받지 못했을경우 진입
                Toast.makeText(getApplicationContext(),"위치정보를 승인하지 않으면 현재위치 기반으로 \n날씨정보를 알려드릴수 없습니다.",Toast.LENGTH_LONG).show();
                getWeather(mavm); //날씨정보 api 호출
            }
        }
    }

 

그럼 이제 우리가 requestLocationUpdates()를 호출했으니 위치정보가 update되었을때 호출하는 콜백함수

onLocationChanged() 만 만들면 완료다.

 

 

 

5. 위치정보 update 되었을때 실행하는 onLocationChanged() 만들기

onLocationChanged() 함수는 위치정보가 update되어졌을때 호출하는 콜백 함수이다.

따라서 우리가 4번 단계에서 위치정보 update를 요청했을때 완료가 되면 해야할 행동은 아래와 같다.

위도와 경도를 입력을 하고 입력한 위도와 경도 출력이다.

(나는 위도와 경도를 입력할수 있도록 Coord 라는 class를 만들고 onCreate()에서 인스턴스(객체)를 생성하였다.)

 

코드는 아래와 같다.

 

    @Override
    public void onLocationChanged(Location location) {
        coord.setLat(location.getLatitude()); //위도를 입력
        coord.setLon(location.getLongitude()); //경도를 입력
        Log.d(TAG,coord.toString()); //입력한 위도와 경두를 출력

        //이건 이제 한번 update하고 나서 위치를 업데이트 다시 안시키기 위해서 하는것임
        //이걸 하지 않으면 위치정보를 계속해서 update하기때문에 배터리 소모하게됨
        lm.removeUpdates(this);
    }

 

 

이렇게 되면 위치정보를 받을수 있게 된다.

나의 전체적인 코드는 아래와 같다.

 

package wook.co.weather.view.splash;

import android.Manifest;
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.Handler;
import android.util.Log;
import android.view.View;
import android.widget.Toast;

import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProvider;

import wook.co.weather.R;
import wook.co.weather.models.dto.Coord;
import wook.co.weather.models.dto.OpenWeather;
import wook.co.weather.models.dto.ShortWeather;
import wook.co.weather.view.MainActivity;
import wook.co.weather.viewmodels.MAgencyViewModel;
import wook.co.weather.viewmodels.WeatherViewModel;

public class SplashActivity extends AppCompatActivity implements LocationListener {

    private ShortWeather sw;
    private MAgencyViewModel mavm;
    private final String TAG = "SplashActivity";
    private LocationManager lm;
    private Coord coord;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.splash_screen);

        //MAgencyViewModel 객체 생성
        mavm = new ViewModelProvider(this).get(MAgencyViewModel.class);

        coord = new Coord();

        //LocationManager 객체 생성
        lm = (LocationManager) getSystemService(Context.LOCATION_SERVICE);

        //위치정보 권한 허용되어 있는지 아닌지를 확인하는 부분
        if(ActivityCompat.checkSelfPermission(SplashActivity.this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED){
            //위치정보 권한 허용되어 있지 않다면 실행하는 코드, 여기서 request에 대한 응답이 나오면 아래에 있는 onRequestPermissionsResult() 함수를 콜백하게 됨
            ActivityCompat.requestPermissions(SplashActivity.this,new String[]{ Manifest.permission.ACCESS_FINE_LOCATION},200); //위치정보 권한을 요청한다.

        }else {
            //위치정보 권한이 허용되어 있을때 실행하는 코드
            Log.d(TAG, "위치정보 허용됨");
            lm.requestLocationUpdates(LocationManager.GPS_PROVIDER,0,0,this);
            getWeather(mavm);
        }

    }

    @Override
    public void onRequestPermissionsResult(int requestCode,String[] permissions,int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);

        if(requestCode == 200){ //permissionCode가 200이고
            if(grantResults[0] == 0){ // 그중 가장 첫번째 result가 0 즉 승인된경우 진입
                Toast.makeText(getApplicationContext(),"위치정보 승인됨",Toast.LENGTH_SHORT).show(); //위치정보 승인됐다고 알리고
                //위치정보 권한을 받았다면 진입
                if(ActivityCompat.checkSelfPermission(SplashActivity.this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED){
                    lm.requestLocationUpdates(LocationManager.GPS_PROVIDER,0,0,this); //위치정보를 update하는 함수
                }
                getWeather(mavm);
            }else{ //위치정보를 허가받지 못했을경우 진입
                Toast.makeText(getApplicationContext(),"위치정보를 승인하지 않으면 현재위치 기반으로 \n날씨정보를 알려드릴수 없습니다.",Toast.LENGTH_LONG).show();
                getWeather(mavm);
            }
        }
    }

    public void getWeather(MAgencyViewModel mavm){
        mavm.init();
        mavm.getWeather().observe(this, new Observer<ShortWeather>() {
            @Override
            public void onChanged(ShortWeather shortWeather) {
                sw = mavm.getWeather().getValue();
                Log.i(TAG,sw.toString());

                Handler handler = new Handler();
                handler.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        //intent 형성한다.
                        Intent intent = new Intent(getApplicationContext(), MainActivity.class);
                        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);//액티비티 스택제거
                        //해당 intent에 객체를 실어서 보낸다.
                        intent.putExtra("shortWeather",sw);
                        startActivity(intent);
                    }
                },1000);
            }
        });
    }

    @Override
    public void onLocationChanged(Location location) {
        coord.setLat(location.getLatitude()); //위도를 입력
        coord.setLon(location.getLongitude()); //경도를 입력
        Log.d(TAG,coord.toString()); //입력한 위도와 경두를 출력

        //이건 이제 한번 update하고 나서 위치를 업데이트 다시 안시키기 위해서 하는것임
        //이걸 하지 않으면 위치정보를 계속해서 update하기때문에 배터리 소모하게됨
        lm.removeUpdates(this);
    }

    @Override
    public void onStatusChanged(String provider, int status, Bundle extras) {

    }

    @Override
    public void onProviderEnabled(String provider) {

    }

    @Override
    public void onProviderDisabled(String provider) {

    }
}
반응형