반응형




Google Map에 목적지 마커를 추가한 후, 사용자가 해당 마커 위치로 이동할 때마다 남은 거리를 계산 해주도록  작성해보았습니다.

2017. 11. 30    최초작성

~~~~~~~~~

2019. 11. 25 FusedLocationProviderClient로 변경




다음 포스팅에 있는  코드를 기반으로 작성되었습니다. 

먼저 아래 코드로 진행해보고 나서 진행하세요..


Android Google Map에 현재 위치 표시하기( FusedLocationProviderClient 사용)

https://webnautes.tistory.com/1249 



GenyMotion을 사용하여 Google Map 테스트를 진행했습니다.

자세한 사용 방법은 다음 포스팅을 참고하세요.


GenyMotion 가상머신에 Google Apps설치하여 Google Maps Android API 테스트 하기

http://webnautes.tistory.com/1064




현재 위치를 시청역으로 설정했습니다.





목적지가 될 회현역에 마커를 추가하기 위해서 오랫동안 클릭하면 다음처럼 다이얼로그 창이 뜹니다.

마커 클릭시 보여줄 정보를 입력한 후, 완료를 클릭합니다. 





빨간색 마커가 추가되며 클릭해보면 좀전에 입력했던 정보를 보여줍니다.





앱 하단의 버튼을 클릭하면 현재 위치와 목적지 마커 사이의  거리 계산을 시작합니다.





현재 위치를 이동시키면 회현역까지 몇미터 남았는지 알려줍니다.

(목적지와의 거리가 몇미터 이내이면 도착으로 할지 결정해서 이후 코딩을 진행하시면 될 듯합니다. )





목적지와 현재 위치간의 거리 계산을 위해서 SphericalUtil의 computeDistanceBetween 메소드를 사용했습니다.


double computeDistanceBetween(LatLng from, LatLng to)





다음처럼 코드 수정을 진행합니다.



1. SphericalUtil를 사용하기 위해서는 build.gradle에 다음 한 줄을 추가해야 합니다. 


dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'androidx.appcompat:appcompat:1.0.2'
    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
    implementation 'com.google.android.gms:play-services-maps:17.0.0'
    implementation 'com.google.android.gms:play-services-location:17.0.0'
    implementation 'com.google.android.material:material:1.1.0-alpha09'
    implementation 'com.google.maps.android:android-maps-utils:0.5'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'androidx.test:runner:1.1.1'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'
}





2. 다음처럼 3개의 변수를 선언합니다. 


    Location mCurrentLocatiion;

    LatLng currentPosition;

    LatLng previousPosition = null;

    Marker addedMarker = null;

    int tracking = 0;



  

3. locationCallback에서 이전 위치와 현재 위치가 다른 경우 (!previousPosition.equals(currentPosition))

정해진 목적지까지의 거리인 500미터이내에 있고(distance < radius) 트래킹 설정 중이고 (tracking == 1)

목적지 마커가 설정되어 있다면 (addedMarker != null)


Toast.makeText 메소드를 사용하여 현재위치와 목적지 사이의 거리를 출력해줍니다. 

거리 계산에는 SphericalUtil.computeDistanceBetween 메소드를 사용했습니다. 


  LocationCallback locationCallback = new LocationCallback() {
        @Override
        public void onLocationResult(LocationResult locationResult) {
            super.onLocationResult(locationResult);

            List<Location> locationList = locationResult.getLocations();

            if (locationList.size() > 0) {
                location = locationList.get(locationList.size() - 1);


                previousPosition = currentPosition;

                currentPosition = new LatLng(location.getLatitude(), location.getLongitude());

                if (previousPosition == null) previousPosition = currentPosition;

                if ( (addedMarker != null) && tracking == 1 ) {
                    double radius = 500; // 500m distance.

                    double distance = SphericalUtil.computeDistanceBetween(currentPosition, addedMarker.getPosition());

                    if ((distance < radius) && (!previousPosition.equals(currentPosition))) {

                        Toast.makeText(MainActivity.this, addedMarker.getTitle() + "까지" + (int) distance + "m 남음", Toast.LENGTH_LONG).show();
                    }
                }

                String markerTitle = getCurrentAddress(currentPosition);
                String markerSnippet = "위도:" + String.valueOf(location.getLatitude())
                        + " 경도:" + String.valueOf(location.getLongitude());

                Log.d(TAG, "onLocationResult : " + markerSnippet);


                //현재 위치에 마커 생성하고 이동
                setCurrentLocation(location, markerTitle, markerSnippet);

                mCurrentLocatiion = location;
            }


        }

    };




4. 원하는 위치를 사용자가 길게 클릭했을 경우  마커를 추가하기 위해서 onMapReady 메서드에 다음 코드를 추가합니다.

    @Override
    public void onMapReady(final GoogleMap googleMap) {
        Log.d(TAG, "onMapReady :");

        mMap = googleMap;


        mMap.setOnMapLongClickListener(new GoogleMap.OnMapLongClickListener(){

            @Override
            public void onMapLongClick(final LatLng latLng) {

                AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
                LayoutInflater inflater = getLayoutInflater();
                View view = inflater.inflate(R.layout.dialog_place_info, null);
                builder.setView(view);
                final Button button_submit = (Button) view.findViewById(R.id.button_dialog_placeInfo);
                final EditText editText_placeTitle = (EditText) view.findViewById(R.id.editText_dialog_placeTitle);
                final EditText editText_placeDesc = (EditText) view.findViewById(R.id.editText_dialog_placeDesc);

                final AlertDialog dialog = builder.create();
                button_submit.setOnClickListener(new View.OnClickListener() {
                    public void onClick(View v) {
                        String string_placeTitle = editText_placeTitle.getText().toString();
                        String string_placeDesc = editText_placeDesc.getText().toString();
                        Toast.makeText(MainActivity.this, string_placeTitle+"\n"+string_placeDesc,Toast.LENGTH_SHORT).show();


                        //맵을 클릭시 현재 위치에 마커 추가
                        MarkerOptions markerOptions = new MarkerOptions();
                        markerOptions.position(latLng);
                        markerOptions.title(string_placeTitle);
                        markerOptions.snippet(string_placeDesc);
                        markerOptions.draggable(true);
                        markerOptions.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_RED));

                        if ( addedMarker != null ) mMap.clear();
                        addedMarker = mMap.addMarker(markerOptions);

                        dialog.dismiss();
                    }
                });

                dialog.show();

            }
        });




5. 위 코드에서 사용한 커스텀 다이얼로그를 위해 레이아웃 파일을 다음처럼 작성합니다.


dialog_place_info.xml


<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/textView_dialog_placeTitle"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true"
        android:layout_alignParentTop="true"
        android:layout_marginLeft="22dp"
        android:layout_marginStart="22dp"
        android:layout_marginTop="26dp"
        android:text="장소 이름" />

    <EditText
        android:id="@+id/editText_dialog_placeTitle"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_marginLeft="37dp"
        android:layout_marginStart="37dp"
        android:layout_marginTop="16dp"
        android:layout_toEndOf="@+id/textView_dialog_placeTitle"
        android:layout_toRightOf="@+id/textView_dialog_placeTitle"
        android:ems="10"
        android:inputType="textPersonName"
        android:text="" />

    <TextView
        android:id="@+id/textView_dialog_placeDesc"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/editText_dialog_placeTitle"
        android:layout_marginTop="16dp"
        android:layout_toLeftOf="@+id/editText_dialog_placeTitle"
        android:layout_toStartOf="@+id/editText_dialog_placeTitle"
        android:text="장소 설명" />

    <EditText
        android:id="@+id/editText_dialog_placeDesc"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignLeft="@+id/editText_dialog_placeTitle"
        android:layout_alignStart="@+id/editText_dialog_placeTitle"
        android:layout_below="@+id/editText_dialog_placeTitle"
        android:ems="10"
        android:inputType="textPersonName"
        android:text="" />

    <Button
        android:id="@+id/button_dialog_placeInfo"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignEnd="@+id/editText_dialog_placeDesc"
        android:layout_alignRight="@+id/editText_dialog_placeDesc"
        android:layout_below="@+id/editText_dialog_placeDesc"
        android:layout_marginTop="26dp"
        android:text="완료" />

</RelativeLayout>






6. 사용자의 현재 위치와 목적지간의 거리 계산을 시작 또는 중지하기 위한 버튼을 지도 아래에 추가해줍니다.


activity_main.xml


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/layout_main"
    android:orientation="vertical"
    tools:context=".MainActivity" >

    <fragment
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="9"
        android:id="@+id/map"
        tools:context=".MapsActivity"
        android:name="com.google.android.gms.maps.SupportMapFragment" />

    <Button
        android:id="@+id/button"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:text="Start" />

</LinearLayout>





7. MainActivity의 OnCreate 메소드에 다음 코드를 추가합니다.

버튼 클릭시 변경되는 트레킹 여부를 저장하기 위해  int 타입의 tracking 변수를 이용했습니다.

초기값은 0으로 해야합니다.

  

      final Button button = (Button)findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                tracking = 1 - tracking;

                if ( tracking == 1){
                    button.setText("Stop");
                }
                else button.setText("Start");
            }
        });



이제 테스트를 해보면 됩니다. 



반응형

포스트 작성시에는 문제 없었지만 이후 문제가 생길 수 있습니다.
댓글로 알려주시면 빠른 시일내에 답변을 드리겠습니다.

여러분의 응원으로 좋은 컨텐츠가 만들어집니다.
지금 본 내용이 도움이 되었다면 유튜브 구독 부탁드립니다. 감사합니다 : )

유튜브 구독하기


제가 쓴 책도 한번 검토해보세요.

  1. 이전 댓글 더보기
  2. 감사합니다. 2018.06.07 01:22

    안녕하세요 잘 배우고 있습니다!
    혹시 이 포스팅과 다른 포스팅을 합쳐서 주변 음식점을 검색하면 나오게 한 후 하나의 마커를 클릭하고 나서 START 버튼을 눌렀을때 그 음식점까지의 거리가 얼마나 되는지 알 수 있는 방법이 있을까요?

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2018.06.07 10:05 신고

      다음 함수의 addedMarker 대신에 클릭한 마커로 바꾸면 될듯합니다.

      double distance = SphericalUtil.computeDistanceBetween(currentPosition, addedMarker.getPosition());

    • 감사합니다. 2018.06.08 00:45

      댓글 감사합니다! 참고하여 바꾸어 보려고 했으나 잘 모르겠어서 다시한번 질문드립니다! 혹시 아래와 같은 방식으로 구글 플레이스를 통해 1000미터 내에 버스정류장을 검색하여 마커를 생성하는 방식인데 어떠한 방법으로 addedMarker대신에 넣어야 할지 알려주실수 있을까요..?? ㅜㅜ


      new NRPlaces.Builder()
      .listener(MainActivity.this)
      .key("구글플레이스AP키")
      .latlng(location.latitude, location.longitude)//현재 위치
      .radius(1000) //1000 미터 내에서 검색
      .type(PlaceType.BUS_STATION) //버스정류장
      .build()
      .execute();

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2018.06.08 14:57 신고

      해당 메소드를 호출하면

      결과는 다음 메소드에서 확인가능합니다.

      @Override
      public void onPlacesSuccess(final List<Place> places) {


      다음처럼 호출한 장소들에 대한 위도, 경도 정보를 가져오게 되는데..

      for (noman.googleplaces.Place place : places) {


      LatLng latLng

      = new LatLng(place.getLatitude()

      , place.getLongitude());


      여기서 얻은 값을 위에 언급한 함수에 넣어주시면 됩니다.



      제 블로그의 다음 포스팅에서 onPlacesSuccess 관련 코드 부분을 참고하세요.

      Places API Web Service를 사용하여 Android Google Map에 현재 위치 주변의 음식점 표시하기
      http://webnautes.tistory.com/1080

    • 질문입니다 2019.11.26 02:31

      안녕하세요 위에 분이 썻던 부분 코드로 구현해보고있는데 질문이 있습니다.
      public void onPlacesSuccess(final List<Place> places) 에 있는 Latlng에 대한 값을 가져오려면 다른 메소드에 있는 변수기 때문에 전역변수로 Latlng를 선언하고 불러와야 하지않나요??

      그래서 전역 변수 List로 선언한 Latlng값들 중에서 클릭한 마커를 불러와야하는데 마커가 여러개다 보니 몇 번째있는 List값을 가져와야할지 모르겠습니다..

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2019.11.26 09:26 신고

      위치 정보를 성공적으로 가져올 때 마다 다음 코드에서 places에 있는 장소 리스트를 전역변수로 넘겨주세요.

      public void onPlacesSuccess(final List<Place> places)

  3. 동동이 2018.11.11 23:42

    안녕하세요 작성하신 글이 도움이 많이 되고있습니다.

    실례하지만 질문하나만 하겠습니다

    두 마커 사이의 거리가 길에 따른 거리인가요 아니면 직선거리인가요?

  4. 학생 2019.04.07 16:29

    현재위치에서 주변음식점 찾는소스에서 넣어보고있는데요..
    start버튼을 누르니 아무것도 실행이안되고 위치정보를 가져올수 없다고 마커에 표시가되는데
    현재위치에서 주변 음식점까지 거리를 구하게 하고싶습니다

    답변 부탁드립니다!!

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2019.04.07 17:04 신고

      로그캣에서 에러 메시지를 찾아야 해결이 가능합니다..

      로그캣을 켜놓고 start버튼을 클릭하면 에러 메시지가 보일겁니다.

  5. 학생 2019.04.08 01:22

    어느곳이 에러인지 잘못찾겠습니다..
    제공해주신 현재위치에서 음식점찾는것에서 거리계산하는 코드를 넣어보았습니다
    잘못된점 지적해주시면 감사하겠습니다
    mainactivity 소스입니다

    public class MainActivity extends AppCompatActivity
    implements OnMapReadyCallback, GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, LocationListener, PlacesListener {

    private GoogleApiClient mGoogleApiClient = null;
    private GoogleMap mGoogleMap = null;
    private Marker currentMarker = null;

    private static final String TAG = "googlemap_example";
    private static final int GPS_ENABLE_REQUEST_CODE = 2001;
    private static final int PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION = 2002;
    private static final int UPDATE_INTERVAL_MS = 1000;
    private static final int FASTEST_UPDATE_INTERVAL_MS = 500;

    private AppCompatActivity mActivity;
    boolean askPermissionOnceAgain = false;
    boolean mRequestingLocationUpdates = false;
    Location mCurrentLocation;
    boolean mMoveMapByUser = true;
    boolean mMoveMapByAPI = true;

    LatLng currentPosition = null;
    LatLng previousPosition = null;
    Marker addedMarker = null;
    int tracking = 0;

    LocationRequest locationRequest = new LocationRequest()
    .setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
    .setInterval(UPDATE_INTERVAL_MS)
    .setFastestInterval(FASTEST_UPDATE_INTERVAL_MS);

    List<Marker> previous_marker =null;
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);


    getWindow().setFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON,
    WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
    setContentView(R.layout.activity_main);

    Log.d(TAG,"onCreate");

    previous_marker = new ArrayList<Marker>();

    final Button button1 = (Button)findViewById(R.id.button1);
    Button button = (Button)findViewById(R.id.button);
    button.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
    showPlaceInformation(currentPosition);

    tracking = 1 - tracking;

    if ( tracking == 1){
    button1.setText("Stop");
    }
    else button1.setText("Start");
    }
    });


    mActivity=this;

    mGoogleApiClient = new GoogleApiClient.Builder(this)
    .addConnectionCallbacks(this)
    .addOnConnectionFailedListener(this)
    .addApi(LocationServices.API)
    .build();

    MapFragment mapFragment = (MapFragment)getFragmentManager()
    .findFragmentById(R.id.map);
    mapFragment.getMapAsync(this);
    }
    @Override
    public void onResume() {

    super.onResume();

    if (mGoogleApiClient.isConnected()) {

    Log.d(TAG, "onResume : call startLocationUpdates");
    if (!mRequestingLocationUpdates) startLocationUpdates();
    }
    if (askPermissionOnceAgain) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
    askPermissionOnceAgain = false;

    checkPermissions();
    }
    }
    }

    private void startLocationUpdates() {

    if (!checkLocationServicesStatus()) {

    Log.d(TAG, "startLocationUpdates : call showDialogForLocationServiceSetting");
    showDialogForLocationServiceSetting();
    }else {

    if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED
    && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {

    Log.d(TAG, "startLocationUpdates : 퍼미션 안가지고 있음");
    return;
    }


    Log.d(TAG, "startLocationUpdates : call FusedLocationApi.requestLocationUpdates");
    LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, locationRequest, this);
    mRequestingLocationUpdates = true;

    mGoogleMap.setMyLocationEnabled(true);

    }

    }

    private void stopLocationUpdates() {

    Log.d(TAG,"stopLocationUpdates : LocationServices.FusedLocationApi.removeLocationUpdates");
    LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);
    mRequestingLocationUpdates = false;
    }

    @Override
    public void onMapReady(GoogleMap googleMap) {
    Log.d(TAG, "onMapReady :");
    mGoogleMap = googleMap;
    setDefaultLocation();

    mGoogleMap.getUiSettings().setMyLocationButtonEnabled(true);
    mGoogleMap.animateCamera(CameraUpdateFactory.zoomTo(15));
    mGoogleMap.setOnMyLocationButtonClickListener(new GoogleMap.OnMyLocationButtonClickListener() {

    @Override
    public boolean onMyLocationButtonClick() {

    Log.d(TAG, "onMyLocationButtonClick : 위치에 따른 카메라 이동 활성화");
    mMoveMapByAPI = true;
    return true;
    }
    });

    mGoogleMap.setOnInfoWindowClickListener(new GoogleMap.OnInfoWindowClickListener() {

    @Override
    public void onInfoWindowClick(Marker marker) {

    Intent intent = new Intent(getBaseContext(), NewActivity.class);

    String title = marker.getTitle();
    String address = marker.getSnippet();

    intent.putExtra("title", title);
    intent.putExtra("address", address);

    startActivity(intent);
    }
    });

    mGoogleMap.setOnMapClickListener(new GoogleMap.OnMapClickListener() {
    @Override
    public void onMapClick(LatLng latLng) {
    Log.d(TAG, "onMapClick");
    }
    });
    mGoogleMap.setOnCameraMoveStartedListener(new GoogleMap.OnCameraMoveStartedListener() {

    @Override
    public void onCameraMoveStarted(int i) {

    if (mMoveMapByUser == true && mRequestingLocationUpdates) {

    Log.d(TAG, "onCameraMove : 위치에 따른 카메라 이동 비활성화");
    mMoveMapByAPI = false;
    }

    mMoveMapByUser = true;

    }
    });

    mGoogleMap.setOnCameraMoveListener(new GoogleMap.OnCameraMoveListener() {

    @Override
    public void onCameraMove() {


    }
    });
    mGoogleMap.setOnMapLongClickListener(new GoogleMap.OnMapLongClickListener(){

    @Override
    public void onMapLongClick(final LatLng latLng) {

    AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
    LayoutInflater inflater = getLayoutInflater();
    View view = inflater.inflate(R.layout.dialog_place_info, null);
    builder.setView(view);
    final Button button_submit = (Button) view.findViewById(R.id.button_dialog_placeInfo);
    final EditText editText_placeTitle = (EditText) view.findViewById(R.id.editText_dialog_placeTitle);
    final EditText editText_placeDesc = (EditText) view.findViewById(R.id.editText_dialog_placeDesc);

    final AlertDialog dialog = builder.create();
    button_submit.setOnClickListener(new View.OnClickListener() {
    public void onClick(View v) {
    String string_placeTitle = editText_placeTitle.getText().toString();
    String string_placeDesc = editText_placeDesc.getText().toString();
    Toast.makeText(MainActivity.this, string_placeTitle+"\n"+string_placeDesc,Toast.LENGTH_SHORT).show();


    //맵을 클릭시 현재 위치에 마커 추가
    MarkerOptions markerOptions = new MarkerOptions();
    markerOptions.position(latLng);
    markerOptions.title(string_placeTitle);
    markerOptions.snippet(string_placeDesc);
    markerOptions.draggable(true);
    markerOptions.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_RED));

    if ( addedMarker != null ) mGoogleMap.clear();
    addedMarker = mGoogleMap.addMarker(markerOptions);

    dialog.dismiss();
    }
    });

    dialog.show();

    }
    });
    }



    @Override
    public void onLocationChanged(Location location) {

    previousPosition = currentPosition;
    currentPosition
    = new LatLng(location.getLatitude(), location.getLongitude());

    if (previousPosition == null) previousPosition = currentPosition;


    if ((addedMarker != null) && tracking == 1) {
    double radius = 500; // 500m distance.

    double distance = SphericalUtil.computeDistanceBetween(currentPosition, addedMarker.getPosition());

    if ((distance < radius) && (!previousPosition.equals(currentPosition))) {

    Toast.makeText(this, addedMarker.getTitle() + "까지" + (int) distance + "m 남음", Toast.LENGTH_LONG).show();


    Log.d(TAG, "onLocationChanged : ");

    String markerTitle = getCurrentAddress(currentPosition);
    String markerSnippet = "위도:" + String.valueOf(location.getLatitude())
    + " 경도:" + String.valueOf(location.getLongitude());

    //현재 위치에 마커 생성하고 이동
    setCurrentLocation(location, markerTitle, markerSnippet);

    mCurrentLocation = location;
    }
    }
    }

    @Override
    protected void onStart() {

    if(mGoogleApiClient != null && mGoogleApiClient.isConnected() == false){

    Log.d(TAG, "onStart: mGoogleApiClient connect");
    mGoogleApiClient.connect();
    }

    super.onStart();
    }

    @Override
    protected void onStop() {

    if (mRequestingLocationUpdates) {

    Log.d(TAG, "onStop : call stopLocationUpdates");
    stopLocationUpdates();
    }

    if ( mGoogleApiClient.isConnected()) {

    Log.d(TAG, "onStop : mGoogleApiClient disconnect");
    mGoogleApiClient.disconnect();
    }

    super.onStop();
    }

    @Override
    public void onConnected(Bundle connectionHint) {


    if ( mRequestingLocationUpdates == false ) {

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {

    int hasFineLocationPermission = ContextCompat.checkSelfPermission(this,
    Manifest.permission.ACCESS_FINE_LOCATION);

    if (hasFineLocationPermission == PackageManager.PERMISSION_DENIED) {

    ActivityCompat.requestPermissions(mActivity,
    new String[]{android.Manifest.permission.ACCESS_FINE_LOCATION},
    PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION);

    } else {

    Log.d(TAG, "onConnected : 퍼미션 가지고 있음");
    Log.d(TAG, "onConnected : call startLocationUpdates");
    startLocationUpdates();
    mGoogleMap.setMyLocationEnabled(true);
    }

    }else{

    Log.d(TAG, "onConnected : call startLocationUpdates");
    startLocationUpdates();
    mGoogleMap.setMyLocationEnabled(true);
    }
    }
    }

    @Override
    public void onConnectionFailed(ConnectionResult connectionResult) {

    Log.d(TAG, "onConnectionFailed");
    setDefaultLocation();
    }


    @Override
    public void onConnectionSuspended(int cause) {

    Log.d(TAG, "onConnectionSuspended");
    if (cause == CAUSE_NETWORK_LOST)
    Log.e(TAG, "onConnectionSuspended(): Google Play services " +
    "connection lost. Cause: network lost.");
    else if (cause == CAUSE_SERVICE_DISCONNECTED)
    Log.e(TAG, "onConnectionSuspended(): Google Play services " +
    "connection lost. Cause: service disconnected");
    }

    public String getCurrentAddress(LatLng latlng) {

    //지오코더... GPS를 주소로 변환
    Geocoder geocoder = new Geocoder(this, Locale.getDefault());

    List<Address> addresses;

    try {

    addresses = geocoder.getFromLocation(
    latlng.latitude,
    latlng.longitude,
    1);
    } catch (IOException ioException) {
    //네트워크 문제
    Toast.makeText(this, "지오코더 서비스 사용불가", Toast.LENGTH_LONG).show();
    return "지오코더 서비스 사용불가";
    } catch (IllegalArgumentException illegalArgumentException) {
    Toast.makeText(this, "잘못된 GPS 좌표", Toast.LENGTH_LONG).show();
    return "잘못된 GPS 좌표";

    }


    if (addresses == null || addresses.size() == 0) {
    Toast.makeText(this, "주소 미발견", Toast.LENGTH_LONG).show();
    return "주소 미발견";

    } else {
    Address address = addresses.get(0);
    return address.getAddressLine(0);
    }

    }


    public boolean checkLocationServicesStatus() {
    LocationManager locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);

    return locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)
    || locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
    }


    public void setCurrentLocation(Location location, String markerTitle, String markerSnippet) {

    mMoveMapByUser = false;


    if (currentMarker != null) currentMarker.remove();


    LatLng currentLatLng = new LatLng(location.getLatitude(), location.getLongitude());

    MarkerOptions markerOptions = new MarkerOptions();
    markerOptions.position(currentLatLng);
    markerOptions.title(markerTitle);
    markerOptions.snippet(markerSnippet);
    markerOptions.draggable(true);


    currentMarker = mGoogleMap.addMarker(markerOptions);


    if ( mMoveMapByAPI ) {

    Log.d( TAG, "setCurrentLocation : mGoogleMap moveCamera "
    + location.getLatitude() + " " + location.getLongitude() ) ;
    // CameraUpdate cameraUpdate = CameraUpdateFactory.newLatLngZoom(currentLatLng, 15);
    CameraUpdate cameraUpdate = CameraUpdateFactory.newLatLng(currentLatLng);
    mGoogleMap.moveCamera(cameraUpdate);
    }
    }


    public void setDefaultLocation() {

    mMoveMapByUser = false;


    //디폴트 위치, Seoul
    LatLng DEFAULT_LOCATION = new LatLng(37.56, 126.97);
    String markerTitle = "위치정보 가져올 수 없음";
    String markerSnippet = "위치 퍼미션과 GPS 활성 요부 확인하세요";


    if (currentMarker != null) currentMarker.remove();

    MarkerOptions markerOptions = new MarkerOptions();
    markerOptions.position(DEFAULT_LOCATION);
    markerOptions.title(markerTitle);
    markerOptions.snippet(markerSnippet);
    markerOptions.draggable(true);
    markerOptions.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_RED));
    currentMarker = mGoogleMap.addMarker(markerOptions);

    CameraUpdate cameraUpdate = CameraUpdateFactory.newLatLngZoom(DEFAULT_LOCATION, 15);
    mGoogleMap.moveCamera(cameraUpdate);

    }


    //여기부터는 런타임 퍼미션 처리을 위한 메소드들
    @TargetApi(Build.VERSION_CODES.M)
    private void checkPermissions() {
    boolean fineLocationRationale = ActivityCompat
    .shouldShowRequestPermissionRationale(this,
    Manifest.permission.ACCESS_FINE_LOCATION);
    int hasFineLocationPermission = ContextCompat.checkSelfPermission(this,
    Manifest.permission.ACCESS_FINE_LOCATION);

    if (hasFineLocationPermission == PackageManager
    .PERMISSION_DENIED && fineLocationRationale)
    showDialogForPermission("앱을 실행하려면 퍼미션을 허가하셔야합니다.");

    else if (hasFineLocationPermission
    == PackageManager.PERMISSION_DENIED && !fineLocationRationale) {
    showDialogForPermissionSetting("퍼미션 거부 + Don't ask again(다시 묻지 않음) " +
    "체크 박스를 설정한 경우로 설정에서 퍼미션 허가해야합니다.");
    } else if (hasFineLocationPermission == PackageManager.PERMISSION_GRANTED) {


    Log.d(TAG, "checkPermissions : 퍼미션 가지고 있음");

    if ( mGoogleApiClient.isConnected() == false) {

    Log.d(TAG, "checkPermissions : 퍼미션 가지고 있음");
    mGoogleApiClient.connect();
    }
    }
    }

    @Override
    public void onRequestPermissionsResult(int permsRequestCode,
    @NonNull String[] permissions,
    @NonNull int[] grantResults) {

    if (permsRequestCode
    == PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION && grantResults.length > 0) {

    boolean permissionAccepted = grantResults[0] == PackageManager.PERMISSION_GRANTED;

    if (permissionAccepted) {


    if ( mGoogleApiClient.isConnected() == false) {

    Log.d(TAG, "onRequestPermissionsResult : mGoogleApiClient connect");
    mGoogleApiClient.connect();
    }

    } else {

    checkPermissions();
    }
    }
    }

    @TargetApi(Build.VERSION_CODES.M)
    private void showDialogForPermission(String msg) {

    AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
    builder.setTitle("알림");
    builder.setMessage(msg);
    builder.setCancelable(false);
    builder.setPositiveButton("예", new DialogInterface.OnClickListener() {
    public void onClick(DialogInterface dialog, int id) {
    ActivityCompat.requestPermissions(mActivity,
    new String[]{android.Manifest.permission.ACCESS_FINE_LOCATION},
    PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION);
    }
    });

    builder.setNegativeButton("아니오", new DialogInterface.OnClickListener() {
    public void onClick(DialogInterface dialog, int id) {
    finish();
    }
    });
    builder.create().show();
    }

    private void showDialogForPermissionSetting(String msg) {

    AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
    builder.setTitle("알림");
    builder.setMessage(msg);
    builder.setCancelable(true);
    builder.setPositiveButton("예", new DialogInterface.OnClickListener() {
    public void onClick(DialogInterface dialog, int id) {

    askPermissionOnceAgain = true;

    Intent myAppSettings = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
    Uri.parse("package:" + mActivity.getPackageName()));
    myAppSettings.addCategory(Intent.CATEGORY_DEFAULT);
    myAppSettings.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    mActivity.startActivity(myAppSettings);
    }
    });
    builder.setNegativeButton("아니오", new DialogInterface.OnClickListener() {
    public void onClick(DialogInterface dialog, int id) {
    finish();
    }
    });
    builder.create().show();
    }

    private void showDialogForLocationServiceSetting() {

    AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.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
    public void onPlacesFailure(PlacesException e) {

    }

    @Override
    public void onPlacesStart() {

    }

    @Override
    public void onPlacesSuccess(final List<Place> places) {

    runOnUiThread(new Runnable() {

    @Override

    public void run() {

    for (noman.googleplaces.Place place : places) {


    LatLng latLng = new LatLng(place.getLatitude(), place.getLongitude());

    String markerSnippet = getCurrentAddress(latLng);

    MarkerOptions markerOptions = new MarkerOptions();
    markerOptions.position(latLng);
    markerOptions.title(place.getName());
    markerOptions.snippet(markerSnippet);
    Marker item = mGoogleMap.addMarker(markerOptions);
    previous_marker.add(item);

    }

    //중복 마커 제거

    HashSet<Marker> hashSet = new HashSet<Marker>();
    hashSet.addAll(previous_marker);
    previous_marker.clear();
    previous_marker.addAll(hashSet);
    }
    });
    }

    public void showPlaceInformation(LatLng location){
    mGoogleMap.clear();

    if(previous_marker!=null)
    previous_marker.clear();

    new NRPlaces.Builder().listener(MainActivity.this).key("api키").latlng(location.latitude, location.longitude).radius(1000).type(PlaceType.PARKING).build().execute();
    }
    @Override
    public void onPlacesFinished() {

    }
    @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(TAG, "onActivityResult : 퍼미션 가지고 있음");


    if ( mGoogleApiClient.isConnected() == false ) {

    Log.d( TAG, "onActivityResult : mGoogleApiClient connect ");
    mGoogleApiClient.connect();
    }
    return;
    }
    }
    break;
    }
    }
    }

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2019.04.08 07:07 신고

      코드를 보고 에러를 찾기는 쉽지가 않습니다... 로그캣에서 찾아야 합니다.

  6. 학생 2019.04.08 12:29

    구글맵을 눌러서 마커를 생성까지는했는데 스타트버튼을눌러도 실행이안됩니다..

    2019-04-08 12:28:10.707 3157-3157/? E/Zygote: isWhitelistProcess - Process is Whitelisted
    2019-04-08 12:28:10.708 3157-3157/? E/Zygote: accessInfo : 1
    2019-04-08 12:28:14.486 3157-3157/com.example.myapplication E/SchedPolicy: set_timerslack_ns write failed: Operation not permitted
    2019-04-08 12:28:18.898 3157-3157/com.example.myapplication E/SchedPolicy: set_timerslack_ns write failed: Operation not permitted
    2019-04-08 12:28:18.910 3157-3157/com.example.myapplication E/ViewRootImpl: sendUserActionEvent() returned.
    2019-04-08 12:28:22.770 3157-3157/com.example.myapplication E/SchedPolicy: set_timerslack_ns write failed: Operation not permitted
    2019-04-08 12:28:23.147 3157-3206/com.example.myapplication E/BufferQueueProducer: [SurfaceTexture-0-3157-0] disconnect: not connected (req=1)

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2019.04.08 19:06 신고

      문제와 관련된 에러 메시지가 없습니다.

      스타트 버튼을 클릭 후 출력되는 로그켓의 메시지를 다시 확인해보세요.

  7. 학생 2019.04.09 00:12

    스타트버튼을누르면 아무것도실행을안합니다 에러또한 안뜹니다
    이경우 자바코드가 잘못된것인가요??
    그리고 위에 댓글을보고 addedmarker 대신 클릭하는 마커로 바꾸라하셧는데 addedmarker부분을 클릭한 마커로 바꾸는것을 어떻게 바꿔야하는지 못찾겠습니다...

  8. 학생 2019.04.09 01:47

    아아 해결했습니다 답변정말 감사합니다
    마지막으로 위에 addedmarker을 클릭 마커로 바꾸는방법을 알고싶습니다!

  9. Favicon of http://www.cyworld.com/01026664196 BlogIcon 도와주세요ㅠ 2019.05.15 21:41

    Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.Button.setOnClickListener(android.view.View$OnClickListener)' on a null object reference
    at com.example.user.gps.MainActivity.onCreate(MainActivity.java:124)
    이것이 오류로 뜨는데 어떡해야되죠ㅠㅠ
    Button 객체가 null 인 상태에서 click리스너를 등록해서 생긴 문제라는데 찾기가 힘드네요

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2019.05.15 22:01 신고

      findviewbyid에 적은 버튼 리소스 이름이 틀리지 않았는지 확인해보세요.

    • 도와주세요ㅠ 2019.05.16 12:12

      button이라는 아이디로 만들었고 그거를 리스너에 아이디 그대로 입력했는데 왜그런걸까요 ㅠ 블로그 내용대로 썼는데..

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2019.05.16 12:28 신고

      레이아웃 파일과 MainActivity에서 버튼 가져오는 부분을 비교해보세요..

      다른 부분때문에 에러일 것 같지는 않습니다.

  10. ㅠㅠ 2019.10.07 23:39

    어플이 실행이 안되고 중지 되여 다른 에러 메시지 안뜨는데 어디가 문제일까요?
    로그켓은 이렇게 나와요
    10-07 23:38:02.438 3516-3516/com.example.map E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.example.map, PID: 3516
    java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.map/com.example.map.MainActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'void com.google.android.gms.maps.MapFragment.getMapAsync(com.google.android.gms.maps.OnMapReadyCallback)' on a null object reference
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2327)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2392)
    at android.app.ActivityThread.access$800(ActivityThread.java:153)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1305)
    at android.os.Handler.dispatchMessage(Handler.java:102)
    at android.os.Looper.loop(Looper.java:135)
    at android.app.ActivityThread.main(ActivityThread.java:5293)
    at java.lang.reflect.Method.invoke(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:372)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)
    Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'void com.google.android.gms.maps.MapFragment.getMapAsync(com.google.android.gms.maps.OnMapReadyCallback)' on a null object reference
    at com.example.map.MainActivity.onCreate(MainActivity.java:111)
    at android.app.Activity.performCreate(Activity.java:5990)
    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1106)
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2280)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2392) 
    at android.app.ActivityThread.access$800(ActivityThread.java:153) 
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1305) 
    at android.os.Handler.dispatchMessage(Handler.java:102) 
    at android.os.Looper.loop(Looper.java:135) 
    at android.app.ActivityThread.main(ActivityThread.java:5293) 
    at java.lang.reflect.Method.invoke(Native Method) 
    at java.lang.reflect.Method.invoke(Method.java:372) 
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903) 
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698) 

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2019.10.08 08:50 신고

      자바코드와 레이아웃에서 MapFragment 대신에 SupportMapFragment를 사용해야 합니다.
      아래 링크를 참고하세요

      https://webnautes.tistory.com/647

  11. Thankswebnautes 2019.10.13 16:56

    글보고 많은 도움 받았습니다!
    저도 지도를 만들려고 하는데 오픈 API를 파싱해서 위치를 나오게 하고싶은데 파싱을 하는법을 모르겠네요..ㅠㅠ
    파싱방법도 글 써주실수는 없을까요...?도움받고싶습니다...

  12. Thankswebnautes 2019.10.14 16:20

    xml입니다!!

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2019.10.14 16:25 신고

      아직 블로그에 XML 파싱관련 글은 없습니다.

      구글에서 android xml parsing라고 검색하시면 원하는 내용을 찾을 수 있습니다.

  13. 2019.11.25 03:37

    비밀댓글입니다

  14. 2019.12.06 03:09

    비밀댓글입니다

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2019.12.06 09:34 신고

      다른 액티비티로 넘어가기전 SharedPreferences 를 사용하여 현재 값들을 저장하고 다시 돌아올때 다시 SharedPreferences를 사용하여 저장된 값을 불러와야 할 듯합니다.

    • 2019.12.06 20:05

      비밀댓글입니다

  15. 정정욱 2019.12.09 15:41

    안녕하세요
    올린 글 중에서..주번 맛집 찾는 글을 봤었는데
    혹시 맛집을 찾고나서 현제 나의 위치에서 선택한 맛집의 거리를 재볼려 하는데 어떻게 접근하면 좋을까요..

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2019.12.09 22:30 신고

      다음 함수를 사용하면 됩니다.

      double distance = SphericalUtil.computeDistanceBetween(currentPosition, addedMarker.getPosition());

  16. 정정욱 2019.12.10 14:31

    previousPosition = currentPosition;

    currentPosition = new LatLng(location.getLatitude(), location.getLongitude());

    if (previousPosition == null) previousPosition = currentPosition;

    if ( (addedMarker != null) && tracking == 1 ) {
    double radius = 500; // 500m distance.

    double distance = SphericalUtil.computeDistanceBetween(currentPosition, addedMarker.getPosition());

    if ((distance < radius) && (!previousPosition.equals(currentPosition))) {

    Toast.makeText(MainActivity.this, addedMarker.getTitle() + "까지" + (int) distance + "m 남음", Toast.LENGTH_LONG).show();
    }
    }
    혹시 이 코드만 쓰면 나오는 걸까요?

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2019.12.10 21:31 신고

      addedMarker.getPosition()가 선택한 맛집에 있는 마커라면 잘 될듯합니다

  17. 안녕하세요 2020.04.02 17:12

    안녕하세요

    전에 올려주신 주변 음식점 자동찾기에 마커까지의 거리계산을 활용해보려 하는데

    addedMarker.getPosition()가 선택한 맛집에 있는 마커라면 잘 될듯합니다" 라고 댓글 달아 주셨는데
    전역변수로 onPlacesSuccess 에서 어떤식으로 값을 받아서 addMarker자리에 넣으면 될까요

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2020.04.02 17:26 신고

      onPlacesSuccess에서 주변 장소의 위치를 가져옵니다. 여기에 거리 측정 기준으로 사용할 위치를 추가하여 계산하면 될듯합니다

  18. 안드로이드촙 2020.04.16 13:46

    안녕하세요. 글 잘보았습니다.
    질문 드릴게 있는데 locationCallback을 통해서 marker를 갱신하게 되는데요.
    제가 구현하고 싶은건 locationCallback을 호출할때마다 제가 이동했던 위치들을 tracking 하기 위해 새롭게 마커를 찍고 싶습니다.

    그럼 markeroption을 새로 생성해서 계속 마커를 셋팅해주어야 하는데,
    이 객체를 자동으로 생성해주는 메서드가 있을까요?

    감사합니다.

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2020.04.16 13:58 신고

      아래 코드만 지우면 현재 위치에 대한 마커가 지워지지않고 계속 남아있게 됩니다.

        if (currentMarker != null) currentMarker.remove();

  19. 조민준 2020.06.06 23:00

    안녕하세요 글 잘봤습니다! 오류도 댓글피드백 보면서 다 해결했습니다!
    다만 제가 구현하고싶은것은 목적지를 두고 이동하는게 아닌
    산책을 하며 이동한 거리계산과 그 이동한 경로를 표시하고 싶습니다.
    if (currentMarker != null) currentMarker.remove(); 이부분을 지우면 마커로
    너무많이 생성되서 마커가 아닌 선으로 이어서 찍어내고 싶은데 혹시 방법이 있을까요?

    • 조민준 2020.06.06 23:03

      혹시 실례가 안된다면 카톡 skilljo24로 피드백 부탁드립니다.. 너무 초보자라 피드백받고싶어서 부탁드립니다! 아니면 이 글에 대댓으로 남겨두셔도 너무너무 감사하겠습니다!

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2020.06.06 23:30 신고

      링크를 참고하여 진행해보세요. 저도 진행해보지는 않았습니다.

      https://developers.google.com/maps/documentation/android-sdk/polygon-tutorial?hl=ko

    • 조민준 2020.06.07 18:22

      혹시 어느부분 코드를 바꿔야하는지도 알려주실수 있을까요?ㅠㅠ

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2020.06.07 18:25 신고

      마커 추가하는 부분에 하면 될듯합니다. 아직 해보지 않은 부분이라 정확한 답변은 어렵습니다.

    • 조민준 2020.06.07 18:29

      아쉽네요 ㅠㅠ
      그래도 칼답 감사합니다!!

    • 조민준 2020.06.07 18:46

      아 혹시 지금 계속 내위치가 로드되면 카메라가 제 위치로 계속 고정이 되는데
      setCurrentLocation(location, markerTitle, markerSnippet);
      이부분 코드를 어떻게 바꾸면 마커는 제위치로 오되 카메라는 자유로울 수 있을까요?

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2020.06.07 18:49 신고

      아래부분만 주석처리하면 카메라가 현재위치를 따라가지 않습니다.

      mMap.moveCamera(cameraUpdate);


      상황에따라 카메라 이동여부를 바꾸면 될듯합니다

    • 조민준 2020.06.07 18:50

      정말정말 감사합니다!! 복받으실거에요!

    • 조민준 2020.06.07 19:56

      혹시 ㅠㅠ 계속 물어봐도 죄송하지만 시작시 기본위치를 서울로 지정하지않고 내위치로 지정하고 싶은데
      public void setDefaultLocation()안에
      LatLng DEFAULT_LOCATION = new LatLng(37.56, 126.97); 이거를
      LatLng DEFAULT_LOCATION = new LatLng(location.getLatitude(), location.getLongitude());이거로 바꿔봤는데 프로그램에서는 오류가 없지만 앱시작이 안됩니다 혹시 방법이 틀린건가요??

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2020.06.07 20:18 신고

      첨에 현재 위치를 가져오는데 까지 시간이 걸리기때문에 초기위치를 서울로 한것입니다.

      앱 종료시 위치를 저장했다가 앱 다시 실행시 저장했던 위치로 이동해도 될듯합니다.

    • 조민준 2020.06.07 20:30

      팁 정말로 감사드립니다 ㅠㅠ

  20. 질문드립니다. 2020.06.16 22:51

    안녕하세요 현재 구현은 제대로 되어있고 if문 하나 빼줘서 마커가 더 생성되는 상황입니다. 이 상황에서 제가 목적지의 위도 경도를 나오게 하고 싶은데 현재 위치의 위도 경도만 표시가 되더라고요 혹시 지정한 마커의 위도 경도 값을 띄우게 하는 방법 알고 싶습니다,. 부탁드립니다,,,ㅜㅜㅜ

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2020.06.17 09:16 신고

      아래 코드 부분에 경도..위도를 추가하면 됩니다.

      markerOptions.title(markerTitle);
              markerOptions.snippet(markerSnippet);

  21. Favicon of https://big-elephant.tistory.com BlogIcon 다들 행복하세요 2020.11.18 20:45 신고

    안녕하세요 포스팅 보고 정말 많은 도움을 받았습니다 감사합니다.
    하나 질문이 있는데 location callback 부분은 어떤 때에 호출되는지 궁금합니다.
    현재 Toast 메시지가 출력 되고 있지 않아 질문 들립니다.(android 가상 기기의 routes 기능으로 테스트 중입니다)

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2020.11.18 20:53 신고

      현재위치가 변경되는 경우에 호출됩니다

    • Favicon of https://big-elephant.tistory.com BlogIcon 다들 행복하세요 2020.11.18 20:57 신고

      빠른 답변 정말 감사드립니다 ㅜㅜ
      if((distance > radius) && (!previousPosition.equals(currentPosition))){
      Toast.makeText(MapActivity.this, "목적지 까지 " + (int)distance + "m 남았습니다", Toast.LENGTH_SHORT);
      }
      이 부분을 작성하지 않더라도 locationCallback의 onLocationResult 메소드가 실행된다는 말씀이신가요?

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2020.11.18 21:24 신고

      네. 이부분은 남은 거리를 출력하기 위한 코드입니다.

    • Favicon of https://big-elephant.tistory.com BlogIcon 다들 행복하세요 2020.11.18 21:41 신고

      답변해주셔서 감사합니다

+ Recent posts