반응형

Places API Web Service를 이용하여 현재 위치 주변의 음식점 정보를 안드로이드의 구글맵에 표시하는 내용을 다룹니다.



Google Maps Android API를 사용하는 방법과  FusedLocationProviderClient 를 이용하여 현재 위치를 구글맵에 표시하는 내용을 다음 두 포스팅에서 다루었습니다.

중복된 내용은 빠져있기 때문에 본 포스팅에 있는 내용을 진행하기 전에 미리 검토해보세요..

 

Google Maps Android API 사용 방법 및 예제

http://webnautes.tistory.com/647 

 

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

https://webnautes.tistory.com/1249 




 2016.12. 4

 2017.11.27  주변 장소의 주소가 한글로 나오도록 수정

 2018. 6. 13 

 2019. 7. 19  FusedLocationProviderClient 사용하도록 수정

 2019. 8. 15  androidx,SupportMapFragment 사용하도록 수정

 2020. 6. 21 문제 발생시 추가

 2020. 9. 13 테스트 및 수정 (  Android Studio 4.0.1, Android 11.0  API 30 )

 2021. 5. 11 테스트 및 수정 (  Android Studio 4.1.3, Android 11.0  API 30 )





1. Places API Web Service 키 얻기


2. Google Map에 현재 위치 주변의 음식점 표시하기


3. 실행 결과


4. 구현시 참고




1. Places API Web Service 키 얻기

현재 위치 주변에 있는 장소를 종류별로 검색하는 기능을 Google Places API for Android에서는 아직 제공하지 않기 때문에 Places API Web Service를 사용합니다.



1. 1. Google Developers Console 사이트 (https://console.developers.google.com/apis/dashboard )에 접속합니다. 



앞에서 Google Map을 위해 생성했던 프로젝트를 선택한 상태에서 진행해야 합니다. 




2. API에 마우스 커서를 가져가면 보이는 메뉴에서 라이브러리를 선택합니다. 

 




3. place api를 검색하여 Places API를 선택합니다.

 




4. 사용을 클릭합니다.

 




5. 왼쪽 위 아이콘을 클릭한 후, 메뉴에서 API 및 서비스 > 사용자 인증 정보를 클릭합니다.

 




6. 사용자 인증 정보 만들기를 클릭하고 메뉴에서 API 키를 선택합니다. 

 




7. 생성된 API 키를 복사해두고  닫기를 클릭합니다. 여기에서 키 제한을 클릭하면 안됩니다. 

 




2. Google Map에 현재 위치 주변의 음식점 표시하기

Places API Web Service에서 제공하는 REST API를 사용하여 현재 위치 주변의 음식점에 대한 정보를 요청하여 획득된 JSON을 파싱하는 작업을 해주면  되지만 여기에서는 간단하게 구현이 가능한 Android-Google-Places-API 라이브러리(https://github.com/nomanr/Android-Google-Places-API)를 사용했습니다.



다음 포스팅에 있는 코드를 기반으로 수정하는 방법을 설명합니다.

 

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

https://webnautes.tistory.com/1249 



레이아웃 파일( activity_main.xml )에 버튼을 추가하고 android:layout_weight 속성으로 화면에 보이는 지도와 버튼의 높이를 조정합니다. 

 

<?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="0.8"
        android:id="@+id/map"
        tools:context=".MapsActivity"
        android:name="com.google.android.gms.maps.SupportMapFragment" />

    <Button
        android:text="장소검색"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="0.2"
        android:id="@+id/button"/>

</LinearLayout>



app 모듈을 위한 build.gradle 파일에서  minSdkVersion15 이상으로 사용해야 합니다. 

 

android {
    compileSdkVersion 29
    buildToolsVersion "29.0.2"
    defaultConfig {
        applicationId "com.tistory.webnautes.googlemaptest"
        minSdkVersion 21
        targetSdkVersion 29
       versionCode 1
        versionName "1.0"
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }



Android-Google-Places-API 라이브러리를 추가해줍니다.  글 작성시점에서  최신 버전은 1.1.3입니다.

변경된 사항을 반영해주기 위해 상단 우측에 보이는  Sync Now를 클릭합니다.

 

dependencies {

    implementation 'noman.placesapi:placesAPI:1.1.3'

}




메니패스트 파일(AndroidManifest.xml)에서 <application> 태그의 allowBackup 속성을 false로 수정하면 해결됩니다.

 

    <application
        android:allowBackup="false"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">





MainActivity에서 PlacesListener 인터페이스를 구현해줘야 합니다.

PlacesListener를 추가해줍니다.

 

public class MainActivity extends AppCompatActivity
        implements
        OnMapReadyCallback,
        ActivityCompat.OnRequestPermissionsResultCallback,
        PlacesListener
{




다음 세 줄을 추가해줍니다.

 

import noman.googleplaces.Place;
import noman.googleplaces.PlacesException;
import noman.googleplaces.PlacesListener;




추가한 인터페이스에서 요구하는 다음 4개의 메소드를 추가해줍니다.

@Override
public void onPlacesFailure(PlacesException e) {

}

@Override
public void onPlacesStart() {

}

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

}

@Override
public void onPlacesFinished() {

}



필요한 변수를 추가해줍니다.

 

List<Marker> previous_marker = null;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);





onPlacesSuccess 메소드의 파라미터 타입에 final을 추가해주고 다음 코드를 입력합니다.

 

@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 = mMap.addMarker(markerOptions);
                    previous_marker.add(item);

                }

                //중복 마커 제거
                HashSet<Marker> hashSet = new HashSet<Marker>();
                hashSet.addAll(previous_marker);
                previous_marker.clear();
                previous_marker.addAll(hashSet);

            }
        });

}



showPlaceInformation() 메소드를 추가해줍니다. 

 "Places API Web Service 키" 부분에 따로 복사해둔 키를 입력하셔야 합니다.

public void showPlaceInformation(LatLng location)
{
	mMap.clear();//지도 클리어

	if (previous_marker != null)
		previous_marker.clear();//지역정보 마커 클리어

	new NRPlaces.Builder()
			.listener(MainActivity.this)
			.key("Places API Web Service 키")
			.latlng(location.latitude, location.longitude)//현재 위치
			.radius(500) //500 미터 내에서 검색
			.type(PlaceType.RESTAURANT) //음식점
			.build()
			.execute();
}




onCreate 메소드에  ArrayList 초기화와 버튼 클릭시 showPlaceInformation() 메소드를 호출하는 코드를 추가합니다.

 

setContentView(R.layout.activity_main);


previous_marker = new ArrayList<Marker>();

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

 

3. 실행 결과

실행하면 현재 위치가 지도에 표시됩니다.

 

주변 영역이 많이 보이도록 지도의 줌을 적당하게 조정한 후,  장소 검색 버튼을 누르면 현재 위치 주변의 음식점 위치들이 지도에 표시됩니다.

 

결과를 가져오는데 좀 시간이 걸립니다. 

 




음식점 위치를 표시하는 마커 하나를 선택하면 음식점 이름과 주소가 나타납니다.

장소 검색버튼을 다시 누르면 기존 마커들을 다지우고 새로 음식점 마커들을 표시합니다.

 



4. 구현시 참고

https://developers.google.com/places/web-service/supported_types?hl=ko 에 있는 Places API Web Service에서 지원되는 장소 유형을  Android-Google-Places-API 라이브러리에서 다음처럼 정의해놓고 있습니다. 

package noman.googleplaces;

/**
* Created by Noman on 8/25/2016.
* https://developers.google.com/places/supported_types
*/
public interface PlaceType {
    public String ACCOUNTING = "accounting";
    public String AIRPORT = "airport";
    public String AMUSEMENT_PARK = "amusement_park";
    public String AQUARIUM = "aquarium";
    public String ART_GALLERY = "art_gallery";
    public String ATM = "atm";
    public String BAKERY = "bakery";
    public String BANK = "bank";
    public String BAR = "bar";
    public String BEAUTY_SALON = "beauty_salon";
    public String BICYCLE_STORE = "bicycle_store";
    public String BOOK_STORE = "book_store";
    public String BOWLING_ALLEY = "bowling_alley";
    public String BUS_STATION = "bus_station";
    public String CAFE = "cafe";
    public String CAMPGROUND = "campground";
    public String CAR_DEALER = "car_dealer";
    public String CAR_RENTAL = "car_rental";
    public String CAR_REPAIR = "car_repair";
    public String CAR_WASH = "car_wash";
    public String CASINO = "casino";
    public String CEMETERY = "cemetery";
    public String CHURCH = "church";
    public String CITY_HALL = "city_hall";
    public String CLOTHING_STORE = "clothing_store";
    public String CONVENIENCE_STORE = "convenience_store";
    public String COURTHOUSE = "courthouse";
    public String DENTIST = "dentist";
    public String DEPARTMENT_STORE = "department_store";
    public String DOCTOR = "doctor";
    public String ELECTRICIAN = "electrician";
    public String ELECTRONICS_STORE = "electronics_store";
    public String EMBASSY = "embassy";
    public String FINANCE = "finance";
    public String FIRE_STATION = "fire_station";
    public String FLORIST = "florist";
    public String FUNERAL_HOME = "funeral_home";
    public String FURNITURE_STORE = "furniture_store";
    public String GAS_STATION = "gas_station";
    public String GYM = "gym";
    public String HAIR_CARE = "hair_care";
    public String HARDWARE_STORE = "hardware_store";
    public String HINDU_TEMPLE = "hindu_temple";
    public String HOME_GOODS_STORE = "home_goods_store";
    public String HOSPITAL = "hospital";
    public String INSURANCE_AGENCY = "insurance_agency";
    public String JEWELRY_STORE = "jewelry_store";
    public String LAUNDRY = "laundry";
    public String LAWYER = "lawyer";
    public String LIBRARY = "library";
    public String LIQUOR_STORE = "liquor_store";
    public String LOCAL_GOVERNMENT_OFFICE = "local_government_office";
    public String LOCKSMITH = "locksmith";
    public String LODGING = "lodging";
    public String MEAL_DELIVERY = "meal_delivery";
    public String MEAL_TAKEAWAY = "meal_takeaway";
    public String MOSQUE = "mosque";
    public String MOVIE_RENTAL = "movie_rental";
    public String MOVIE_THEATER = "movie_theater";
    public String MOVING_COMPANY = "moving_company";
    public String MUSEUM = "museum";
    public String NIGHT_CLUB = "night_club";
    public String PAINTER = "painter";
    public String PARK = "park";
    public String PARKING = "parking";
    public String PET_STORE = "pet_store";
    public String PHARMACY = "pharmacy";
    public String PHYSIOTHERAPIST = "physiotherapist";
    public String PLUMBER = "plumber";
    public String POLICE = "police";
    public String POST_OFFICE = "post_office";
    public String REAL_ESTATE_AGENCY = "real_estate_agency";
    public String RESTAURANT = "restaurant";
    public String ROOFING_CONTRACTOR = "roofing_contractor";
    public String RV_PARK = "rv_park";
    public String SCHOOL = "school";
    public String SHOE_STORE = "shoe_store";
    public String SHOPPING_MALL = "shopping_mall";
    public String SPA = "spa";
    public String STADIUM = "stadium";
    public String STORAGE = "storage";
    public String STORE = "store";
    public String SUBWAY_STATION = "subway_station";
    public String SYNAGOGUE = "synagogue";
    public String TAXI_STAND = "taxi_stand";
    public String TRAIN_STATION = "train_station";
    public String TRANSIT_STATION = "transit_station";
    public String TRAVEL_AGENCY = "travel_agency";
    public String UNIVERSITY = "university";
    public String VETERINARY_CARE = "veterinary_care";
    public String ZOO = "zoo";

}



showPlaceInformation() 메소드에서 PlaceType.RESTAURANT를 필요시 위에 나온 원하는 타입으로 바꾸시면 됩니다. 

public void showPlaceInformation(LatLng location)
{
	mGoogleMap.clear();//지도 클리어

	if (previous_marker != null)
		previous_marker.clear();//지역정보 마커 클리어

	new NRPlaces.Builder()
			.listener(MainActivity.this)
			.key("Places API Web Service 키")
			.latlng(location.latitude, location.longitude)//현재 위치
			.radius(500) //500 미터 내에서 검색
			.type(PlaceType.RESTAURANT) //음식점
                  .language("ko", "KR")
			.build()
			.execute();
}


 

.type(PlaceType.RESTAURANT)를 지우면 주변에 있는 모든 타입의 장소가 검색됩니다.



5. 문제 발생시

로그캣에서 Place API 관련 주소를 찾을 수 있습니다. 

해당 주소를 복사하여  웹브라우저에 붙여넣기 해보세요.



다음과 같은 에러가 발생한다면..

{

   "error_message" : "You must enable Billing on the Google Cloud Project at https://console.cloud.google.com/project/_/billing/enable Learn more at https://developers.google.com/maps/gmp-get-started",

   "html_attributions" : [],

   "results" : [],

   "status" : "REQUEST_DENIED"

}



구글 클라우드 플랫폼에서 다음처럼 결재 수단을 선택하여 

신용 카드 또는 체크 카드를 등록해야 정상적으로 주변 장소 정보를 받을 수 있습니다. 

 

 

반응형

해본 것을 문서화하여 기록합니다.


포스트 작성시에는 문제 없었지만 이후 문제가 생길 수 있습니다.
질문을 남겨주면 가능한 빨리 답변드립니다.


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

  • 네이버 블러그 공유하기
  • 네이버 밴드에 공유하기
  • 페이스북 공유하기
  • 카카오스토리 공유하기

댓글을 달아 주세요

">
  1. 이전 댓글 더보기
  2. thumbnail
    qpwpdpwpd
    2020.09.21 20:37

    잘 보고갑니다.
    빨간 마커 색상 대신 다른 색상으로 변경은 불가한가요?

    • thumbnail
      Favicon of https://webnautes.tistory.com BlogIcon webnautes
      2020.09.21 20:50 신고

      아래처럼 바꾼다고 하네요

      static final LatLng MELBOURNE = new LatLng(-37.813, 144.962);
      Marker melbourne = mMap.addMarker(new MarkerOptions()
                                .position(MELBOURNE)
                                .icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_AZURE)));


      HUE_AZURE 정의를 가보면 다른색도 있을겁니다.

  3. thumbnail
    qpwpdpwpd
    2020.09.22 11:28

    덕분에 수정했습니다.
    감사합니다.

  4. thumbnail
    개바르자가될테다
    2020.10.06 01:58

    안녕하세요 개발자님!! 제가지금
    .type(PlaceType.RESTAURANT) 타입 설정하는데 애먹고있는데요
    타입을 여러개 설정할 수 있는 방법은 없는걸까요??

    new NRPlaces.Builder() 하나의 빌더에 하나의 타입만 설정 가능한건지 여쭙습니다!

    • thumbnail
      Favicon of https://webnautes.tistory.com BlogIcon webnautes
      2020.10.06 07:05 신고

      하나만 가능할듯 합니다.

    • thumbnail
      BlogIcon 개바르자가될테다
      2020.10.08 18:43

      new NRPlaces.Builder() 로 빌더를 여러개 생성 해주는 방식으로 해결했습니다. 하나의 빌더를 생성하면서 검색, 마커설정이 되는데 여러개의 빌더를 생성하면서 검색을 반복하는 형태로 문제를 해결했네요.. 최적의 해결법인지는 모르겠지만.. 여튼 감사합니다 !

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

      아 그런방법이 있었네요. 잘하셨네요

  5. thumbnail
    2020.10.11 12:56

    비밀댓글입니다

  6. thumbnail
    Favicon of https://as1212.tistory.com BlogIcon sangjaemm

    Android Google Map에 현재 위치 표시하기( FusedLocationProviderClient 사용) 에서 만든 프로젝트 그러니까 google maps android api test프로젝트에 places api추가하는게 맞나요? 추가했는데 현재위치만 빨간마크로 표시되네요 ..

    • thumbnail
      Favicon of https://webnautes.tistory.com BlogIcon webnautes
      2020.11.15 22:48 신고

      네 맞습니다. 혹시 로그캣에 인증 오류가 난건 아닌지 확인해보세요. URL이 보일텐데 웹브라우저에서 접속시 에러없이 장소목록이 보여야합니다.

    • thumbnail
      Favicon of https://as1212.tistory.com BlogIcon sangjaemm
      2020.11.18 19:44 신고

      https://console.developers.google.com 에 해당 프로젝트에 들어가보니까 places api 오류율이 100%라고 되어있는데 인증에 문제가 있는건가요? 참고로 에뮬레이터입니다

    • thumbnail
      Favicon of https://as1212.tistory.com BlogIcon sangjaemm
      2020.11.18 20:00 신고

      글고 URL은 어디있나요..

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

      안드로이드 스튜다오의 logcat에서 찾을수 있습니다. 에뮬레이터에는 gps가 없어서 동작하지 않을듯합니다

  7. thumbnail
    Favicon of https://jcw3898.tistory.com BlogIcon 코딩좀잘해보자

    String markerSnippet = getCurrentAddress(latLng); 에서
    getCurrentAddress 부분만 빨간표시로 뜨고 다른 곳은 에러가 없는데
    함수를 따로 만들어야하나요? 작성하신 그대로 따라했는데.. 알려주시면 정말 감사하겠습니다!

    • thumbnail
      Favicon of https://webnautes.tistory.com BlogIcon webnautes
      2020.11.20 23:15 신고

      본 포스트의 코드는 다음 포스트에 이어서 작성해야 하는 코드입니다.

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

      https://webnautes.tistory.com/1249

  8. thumbnail
    Favicon of https://eager031.tistory.com BlogIcon Eckert

    안녕하세요 블로그글보며 열심히 공부중인 학생입니다.

    현재 마커를 클릭하거나 화면을 움직이면 움직인 화면이 고정되지 않고 내 중심 화면으로 다시 되돌아오는데 어떤 부분이 문제인가요?

    댓글 중간에 있는 것을 참조하며 바꾸었는데.. 에러가 뜹니다.

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


    boolean user = 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);

    mMap.setOnMyLocationButtonClickListener(new GoogleMap.OnMyLocationButtonClickListener(){
    @Override
    public boolean onMyLocationButtonClick()
    {
    user = false;

    return false;
    }
    });


    currentMarker = mMap.addMarker(markerOptions);
    if( user == false ){
    CameraUpdate cameraUpdate = CameraUpdateFactory.newLatLng(currentLatLng);
    mMap.moveCamera(cameraUpdate);
    }


    }
    댓글 참조하여 변경한 코드입니다. 중간 user = false; 부분 중 user 부분이 계속 에러가 뜨는데 방향을 어찌 잡아야 할까요?

    • thumbnail
      Favicon of https://eager031.tistory.com BlogIcon Eckert
      2020.11.24 19:59 신고

      전 글에 setCurrentLocation 부분을 주석처리하면 된다고 하셨는데, 혹시 어떤 부분인지 알 수 있을까요?

    • thumbnail
      Favicon of https://webnautes.tistory.com BlogIcon webnautes
      2020.11.24 20:00 신고

      다음 코드를 동작 못하게 막으면 이동하지 않습니다. 사용자가 지도 터치하면 동작못하게 막았다가 현재 위치 버튼을 누르면 다시 동작하도록 하면됩니다.

      방법은 하신대로 불린 변수를 하나 선언하면 될듯합니다.

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

    • thumbnail
      Favicon of https://eager031.tistory.com BlogIcon Eckert
      2020.11.24 20:07 신고

      불린 변수를 하나 선언하신다는 말씀이 이해가 되지 않습니다.. 혹시 어떤걸 어느 부분에 추가하면 될까요?

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

      작성하신 다음 코드를 사용하면 됩니다.
      전역변수로 선언하세요.

      boolean user = false;

  9. thumbnail
    Favicon of https://eager031.tistory.com BlogIcon Eckert

    감사합니다,,다른 방법인 mMap.moveCamera(cameraUpdate) 요쪽을 주석처리해보니 마커 클릭시에도 카메라 내위치 고정은 안되더군요.

    다만 어플 초기 실행시 현재 내 GPS 위치가 아닌 초기설정 위치로 실행이 되는데, 이는 위 구문을 주석처리해서 발생하는 현상인가요?

    또한 화면 을 터치로 이동후에 해당 화면 기준에서 장소검색을 다시 실행하고 싶은데, 참고할만한 글이나 코드가 있을까요?

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

      setCurrentLocation을 주석처리하면 위치 이동시 화면이 따라 움직이지 않지 않나요?
      이 함수를 이용해 현재 위치와 카메라를 조정합니다. 언급하신 함수도 이 내부에 있지않나요?

      초기 위치로 서울을 보여주도록 하고 있습니다. 그러지 않으면 미국이나 바다 한가운데가 잠시 보이기 때문입니다.

    • thumbnail
      Favicon of https://eager031.tistory.com BlogIcon Eckert
      2020.11.25 17:33 신고

      말씀하신 주석처리 부분이
      //현재 위치에 마커 생성하고 이동
      setCurrentLocation (location, markerTitle, markerSnippet); 이 부분인가요? 주석처리하게되면 화면이 마커를 중심으로 따라 움직이긴 하는데 어플 초기 실행시 초기 위치로 화면이 잡혀서 고민중입니다

    • thumbnail
      Favicon of https://webnautes.tistory.com BlogIcon webnautes
      2020.11.25 17:49 신고

      화면 터치시 이 함수를 작동안하게 해보면 현재위치따라 화면이 이동하지 않게됩니다

    • thumbnail
      Favicon of https://eager031.tistory.com BlogIcon Eckert
      2020.11.25 20:34 신고

      감사합니다!!

  10. thumbnail
    Favicon of https://btsdaily.tistory.com BlogIcon 데이일리

    안녕하세요 개발자님 코드와 설명 너무 큰 도움이 되어 감사합니다 ㅠㅠ 현재 대학교 3학년에 재학중인데 안드로이드 스튜디오를 처음 접하게 되어 구글맵을 바로 연동해보려하니 이해안되는게 확실히 많네요 ㅠㅠㅠ 2018년도부터의 이전 댓글들도 많이 봤는데 하다보니 약간 오류라고 해야할까요 제가 원하는대로 되지 않는게 많습니다 ㅠㅠ 도움주시면 감사하겠습니다 ㅠㅠ
    1. 자꾸 주소 미발견 메시지가 뜸
    2. 새로운 마커 생성은 가능하나 새로운 마커 생성 후 바로 카메라가 현재위치로 돌아옴
    3. 주소 미발견 문제 때문인지 현재위치에서 푸른색 범위가 표시되지 않음.
    이러한 오류가 발생되는데 코드보시고 답변주시면 정말 감사하겠습니다...ㅠㅠ
    그리고 새로 추가했으면 하는게 있는데 참고글이나 문헌 주시면 정말 절하겠습니다 ㅠㅠ
    1. 새로운 마커를 생성하면 그 위치에서 장소 검색을 했을 때 그주변의 카페가 나타났으면 좋겠습니다... 이경우 코드를 많이 바꿔야할까요? ㅠㅠ
    package com.example.cafebooking;

    import androidx.annotation.NonNull;
    import androidx.appcompat.app.AlertDialog;
    import androidx.appcompat.app.AppCompatActivity;
    import androidx.core.app.ActivityCompat;
    import androidx.core.content.ContextCompat;

    import android.Manifest;
    import android.content.DialogInterface;
    import android.content.Intent;
    import android.content.pm.PackageManager;
    import android.location.Address;
    import android.location.Geocoder;
    import android.location.Location;
    import android.location.LocationManager;
    import android.os.Bundle;
    import android.os.Looper;
    import android.util.Log;
    import android.view.View;
    import android.view.WindowManager;
    import android.widget.Button;
    import android.widget.Toast;

    import com.google.android.gms.location.FusedLocationProviderClient;
    import com.google.android.gms.location.LocationCallback;
    import com.google.android.gms.location.LocationRequest;
    import com.google.android.gms.location.LocationResult;
    import com.google.android.gms.location.LocationServices;
    import com.google.android.gms.location.LocationSettingsRequest;
    import com.google.android.gms.maps.CameraUpdate;
    import com.google.android.gms.maps.CameraUpdateFactory;
    import com.google.android.gms.maps.GoogleMap;
    import com.google.android.gms.maps.OnMapReadyCallback;
    import com.google.android.gms.maps.SupportMapFragment;
    import com.google.android.gms.maps.model.BitmapDescriptorFactory;
    import com.google.android.gms.maps.model.LatLng;
    import com.google.android.gms.maps.model.Marker;
    import com.google.android.gms.maps.model.MarkerOptions;
    import com.google.android.material.snackbar.Snackbar;

    import java.io.IOException;
    import java.util.ArrayList;
    import java.util.HashSet;
    import java.util.List;
    import java.util.Locale;

    import noman.googleplaces.NRPlaces;
    import noman.googleplaces.Place;
    import noman.googleplaces.PlaceType;
    import noman.googleplaces.PlacesException;
    import noman.googleplaces.PlacesListener;

    public class MapAPI extends AppCompatActivity
    implements OnMapReadyCallback,
    GoogleMap.OnMarkerClickListener,
    ActivityCompat.OnRequestPermissionsResultCallback,
    PlacesListener {

    @Override
    public boolean onMarkerClick(Marker marker) {
    Intent intent = new Intent(MapAPI.this, MapChoice.class);
    startActivity(intent);
    return false;
    }

    @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 = mMap.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)
    {
    mMap.clear();

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

    new NRPlaces.Builder()
    .listener(MapAPI.this)
    .key("AIzaSyDjU2FHyOIJdJZ9GpYprwIpzLwLq1qHrz8")
    .latlng(location.latitude, location.longitude)
    .radius(10000)
    .type(PlaceType.CAFE)
    .build()
    .execute();
    }

    @Override
    public void onPlacesFinished() {

    }


    private GoogleMap mMap;
    private Marker currentMarker = null;

    private static final String TAG = "googlemap_example";
    private static final int GPS_ENABLE_REQUEST_CODE = 2001;
    private static final int UPDATE_INTERVAL_MS = 1000; // 1초
    private static final int FASTEST_UPDATE_INTERVAL_MS = 500; // 0.5초


    private static final int PERMISSIONS_REQUEST_CODE = 100;
    boolean needRequest = false;


    String[] REQUIRED_PERMISSIONS = {Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION}; // 외부 저장소


    Location mCurrentLocatiion;
    LatLng currentPosition;


    private FusedLocationProviderClient mFusedLocationClient;
    private LocationRequest locationRequest;
    private Location location;


    private View mLayout;

    boolean user = false;

    List<Marker> previous_marker = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    getWindow().setFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON,
    WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);

    setContentView(R.layout.activity_map);

    previous_marker = new ArrayList<Marker>();

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

    mLayout = findViewById(R.id.layout_main);

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


    LocationSettingsRequest.Builder builder =
    new LocationSettingsRequest.Builder();

    builder.addLocationRequest(locationRequest);


    mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this);


    SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
    .findFragmentById(R.id.map);
    mapFragment.getMapAsync(this);
    }

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

    mMap = googleMap;

    setDefaultLocation();


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



    if (hasFineLocationPermission == PackageManager.PERMISSION_GRANTED &&
    hasCoarseLocationPermission == PackageManager.PERMISSION_GRANTED ) {



    startLocationUpdates();

    }else {

    if (ActivityCompat.shouldShowRequestPermissionRationale(this, REQUIRED_PERMISSIONS[0])) {

    Snackbar.make(mLayout, "이 앱을 실행하려면 위치 접근 권한이 필요합니다.",
    Snackbar.LENGTH_INDEFINITE).setAction("확인", new View.OnClickListener() {

    @Override
    public void onClick(View view) {

    ActivityCompat.requestPermissions( MapAPI.this, REQUIRED_PERMISSIONS,
    PERMISSIONS_REQUEST_CODE);
    }
    }).show();


    } else {
    ActivityCompat.requestPermissions( this, REQUIRED_PERMISSIONS,
    PERMISSIONS_REQUEST_CODE);
    }

    }



    mMap.getUiSettings().setMyLocationButtonEnabled(true);

    mMap.setOnMapClickListener(new GoogleMap.OnMapClickListener() {
    @Override
    public void onMapClick(LatLng latLng) {

    Log.d( TAG, "onMapClick :");
    MarkerOptions marker = new MarkerOptions().position(
    new LatLng(latLng.latitude, latLng.longitude)).title("New Marker");

    googleMap.addMarker(marker);

    System.out.println(latLng.latitude+"---"+ latLng.longitude);

    }
    });
    }

    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);
    //location = locationList.get(0);

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


    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;
    }


    }

    };



    private void startLocationUpdates() {

    if (!checkLocationServicesStatus()) {

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

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



    if (hasFineLocationPermission != PackageManager.PERMISSION_GRANTED ||
    hasCoarseLocationPermission != PackageManager.PERMISSION_GRANTED ) {

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


    Log.d(TAG, "startLocationUpdates : call mFusedLocationClient.requestLocationUpdates");

    mFusedLocationClient.requestLocationUpdates(locationRequest, locationCallback, Looper.myLooper());

    if (checkPermission())
    mMap.setMyLocationEnabled(true);

    }

    }


    @Override
    protected void onStart() {
    super.onStart();

    Log.d(TAG, "onStart");

    if (checkPermission()) {

    Log.d(TAG, "onStart : call mFusedLocationClient.requestLocationUpdates");
    mFusedLocationClient.requestLocationUpdates(locationRequest, locationCallback, null);

    if (mMap!=null)
    mMap.setMyLocationEnabled(true);

    }


    }


    @Override
    protected void onStop() {

    super.onStop();

    if (mFusedLocationClient != null) {

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




    public String getCurrentAddress(LatLng latlng) {

    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).toString();
    }

    }


    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) {

    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(false);


    currentMarker = mMap.addMarker(markerOptions);

    mMap.setOnMyLocationButtonClickListener(new GoogleMap.OnMyLocationButtonClickListener(){
    @Override
    public boolean onMyLocationButtonClick()
    {
    user = false;

    return false;
    }
    });

    if(user == false) {
    CameraUpdate cameraUpdate = CameraUpdateFactory.newLatLng(currentLatLng);
    mMap.moveCamera(cameraUpdate);
    }

    }


    public void setDefaultLocation() {


    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 = mMap.addMarker(markerOptions);

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

    }

    private boolean checkPermission() {

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



    if (hasFineLocationPermission == PackageManager.PERMISSION_GRANTED &&
    hasCoarseLocationPermission == PackageManager.PERMISSION_GRANTED ) {
    return true;
    }

    return false;

    }


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

    if ( permsRequestCode == PERMISSIONS_REQUEST_CODE && grandResults.length == REQUIRED_PERMISSIONS.length) {


    boolean check_result = true;



    for (int result : grandResults) {
    if (result != PackageManager.PERMISSION_GRANTED) {
    check_result = false;
    break;
    }
    }


    if ( check_result ) {

    startLocationUpdates();
    }
    else {

    if (ActivityCompat.shouldShowRequestPermissionRationale(this, REQUIRED_PERMISSIONS[0])
    || ActivityCompat.shouldShowRequestPermissionRationale(this, REQUIRED_PERMISSIONS[1])) {


    Snackbar.make(mLayout, "퍼미션이 거부되었습니다. 앱을 다시 실행하여 퍼미션을 허용해주세요. ",
    Snackbar.LENGTH_INDEFINITE).setAction("확인", new View.OnClickListener() {

    @Override
    public void onClick(View view) {

    finish();
    }
    }).show();

    }else {


    Snackbar.make(mLayout, "퍼미션이 거부되었습니다. 설정(앱 정보)에서 퍼미션을 허용해야 합니다. ",
    Snackbar.LENGTH_INDEFINITE).setAction("확인", new View.OnClickListener() {

    @Override
    public void onClick(View view) {

    finish();
    }
    }).show();
    }
    }

    }
    }


    private void showDialogForLocationServiceSetting() {

    AlertDialog.Builder builder = new AlertDialog.Builder(MapAPI.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:

    if (checkLocationServicesStatus()) {
    if (checkLocationServicesStatus()) {

    Log.d(TAG, "onActivityResult : GPS 활성화 되있음");


    needRequest = true;

    return;
    }
    }

    break;
    }
    }



    }

    • thumbnail
      Favicon of https://webnautes.tistory.com BlogIcon webnautes
      2020.12.04 21:41 신고

      다음 코드에 지정된 타입을 CAFE로 바꾸면 카페로 검색이 됩니다.

      .type(PlaceType.RESTAURANT) //음식점


      화면 이동 문제는 Eckert님에게 답변한 내용을 확인해보세요.

  11. thumbnail
    Favicon of https://btsdaily.tistory.com BlogIcon 데이일리

    추가 질문드립니다.. 위에분 말대로 해보고싶은데 완전 안드로이드와 자바 초보자라 잘 이해가 안돼서요 ㅠㅠ 코드로 설명 부탁드려도 될까요 ㅠㅠㅠ 그리고 타입은 CAFE로 변경했는데 그 마커를 새로 생성한 지역에서 장소검색을 하고 싶은거라서요 ㅠㅠ 카페출력이 안되는게 아니라 ㅠㅠ 그건 어떻게 해결하는게 좋을까요... 마지막으로 주소 미발견이라고 자꾸 뜨는데 카페 검색은 잘되거든요..? 이건 왜 이러는걸까요 ㅠㅠ 답변 부탁드립니다 ㅠㅠ

    • thumbnail
      Favicon of https://webnautes.tistory.com BlogIcon webnautes
      2020.12.05 14:36 신고

      주소 미발견은 어쩔 수 없습니다. 아마 GPS로 얻은 위치에 대한 좌표의 정보를 얻지 못해서 입니다.

      막힐때에는 구글에서 검색해보는게 답입니다.

      다음 두 링크를 참고해보세요

      https://m.blog.naver.com/PostView.nhn?blogId=qbxlvnf11&logNo=221182081995&proxyReferer=https:%2F%2Fwww.google.com%2F


      http://www.masterqna.com/android/54015/%EA%B5%AC%EA%B8%80%EB%A7%B5%EC%9D%98-%ED%98%84%EC%9E%AC-%EC%9C%84%EC%B9%98-%EB%B2%84%ED%8A%BC%EC%9D%98-%EC%9D%B4%EB%B2%A4%ED%8A%B8-%40

  12. thumbnail
    Favicon of https://vlsn.tistory.com BlogIcon vlsn

    구글링을 하다가 찾지못해서 질문합니다 ㅠㅠ 저는 현재위치말고 마커 근처에 정보를 나오게 하고 싶은데 어떻게해야할지 감이 안와서요 ㅠㅠ 만들긴했는데 값을 못받아오는거같아서
    혹시 방법이 있을까요!?

    • thumbnail
      Favicon of https://vlsn.tistory.com BlogIcon vlsn
      2020.12.28 15:35 신고

      추가적으로 여기서 에러가 나는데... "Places API Web Service 키" 키설정을 제한없음으로하면 패키지와 프로젝트 상관없이 다 쓸수있는건가요!?

    • thumbnail
      Favicon of https://webnautes.tistory.com BlogIcon webnautes
      2020.12.28 17:14 신고

      다음 부분에 마커좌표를 입력하세요

      .latlng(location.latitude, location.longitude)//현재 위치

      인증키를 등록한 안드로이드폰에서만 동작할겁니다. 배포용 키를 만들어보지 않아서 이부분은 답변드리기 어렵습니다.

    • thumbnail
      Favicon of https://webnautes.tistory.com BlogIcon webnautes
      2020.12.28 17:15 신고

      안드로이드폰이 아니라 해당 앱일겁니다.

    • thumbnail
      Favicon of https://vlsn.tistory.com BlogIcon vlsn
      2020.12.29 00:44 신고

      정말 감사합니다!!!ㅠㅜ 너무 디테일하게 설명잘해주셔서 도움 많이받고있습니다!!! 유튜브도 너무 좋아요!

    • thumbnail
      Favicon of https://webnautes.tistory.com BlogIcon webnautes
      2020.12.29 07:30 신고

      감사합니다

  13. thumbnail
    Favicon of https://lolou.tistory.com BlogIcon 의도_

    혹시 프래그먼트에서 runOnUiThread 이 부분이 빨간색으로 오류가 뜨는데 어떻게 해결해 주면 좋을까요??

    • thumbnail
      Favicon of https://webnautes.tistory.com BlogIcon webnautes
      2021.01.25 18:24 신고

      오류 메시지를 확인해야 합니다. 코드를 그대로 사용했나요?

    • thumbnail
      Favicon of https://lolou.tistory.com BlogIcon 의도_
      2021.01.25 18:31 신고

      네 코드를 그대로 사용했어요
      private void runOnUiThread(Runnable runnable) {
      }
      일단 그 부분에 대해 위와같이 메소드를 만들어 주니 빨간줄은 사라졌는데,

      실행 후
      버튼을 누르면 앱이 종료되고
      이런 오류가 뜹니다.

      2021-01-25 18:38:45.745 32148-32148/com.leebbr.favorite E/AndroidRuntime: FATAL EXCEPTION: main
      Process: com.leebbr.favorite, PID: 32148
      java.lang.NullPointerException: Attempt to read from field 'double com.google.android.gms.maps.model.LatLng.latitude' on a null object reference
      at com.leebbr.favorite.Fragment1.showPlaceInformation(Fragment1.java:564)
      at com.leebbr.favorite.Fragment1$1.onClick(Fragment1.java:162)

      564번째 줄은 .latlng(location.latitude, location.longitude)//현재 위치

      showPlaceInformation메소드에서 현재위치 넣는 부분이고

      162번째 줄은
      onCreateView안에 넣은
      onClick 시 구현되는 showPlaceInformation(currentPosition);
      이 부분이에요..

      그리고 showPlaceInformation(currentPosition); 이 부분도 로그를 찍어보니 currentPosition에 null 이 찍혀요..

    • thumbnail
      Favicon of https://lolou.tistory.com BlogIcon 의도_
      2021.01.25 19:03 신고

      .key("AIzaSyB8Ox3AIuecP31-cPO842SApQkloJ4avCs")
      .latlng(location.latitude, location.longitude)//현재 위치

      이 두 부분을 왔다갔다하면서 오류가 나네유.....ㅠ

    • thumbnail
      Favicon of https://webnautes.tistory.com BlogIcon webnautes
      2021.01.25 20:46 신고

      currentPosition 변수에 값이 왜 입력안되는 지 확인해보세요.

    • thumbnail
      Favicon of https://lolou.tistory.com BlogIcon 의도_
      2021.01.25 22:18 신고

      혹시 몰라서 다시 새 프로젝트에 프래그먼트 말고 액티비티로 처음부터 구현해 보았는데 이런에러가 나와요
      2021-01-25 22:16:15.989 1043-1534/com.leebbr.nowposition E/Places: https://maps.googleapis.com/maps/api/place/nearbysearch/json?key=AIzaSyB8Ox3AIuecP31-cPO842SApQkloJ4avCs&location=37.5935317,126.9330928&radius=500&type=restaurant
      2021-01-25 22:16:16.134 1043-1534/com.leebbr.nowposition E/Places: noman.googleplaces.PlacesException: REQUEST_DENIED

      주소 클릭하면 아래와 같은 내용
      {
      "error_message" : "This IP, site or mobile application is not authorized to use this API key. Request received from IP address 121.128.140., with empty referer",
      "html_attributions" : [],
      "results" : [],
      "status" : "REQUEST_DENIED"
      }

      API 키를 사용할 수있는 권한이 없다는건데,,,, 아무리 찾아봐도 모르겠어요,,

    • thumbnail
      Favicon of https://lolou.tistory.com BlogIcon 의도_
      2021.01.25 22:31 신고

      앗 해결했어요!!!!!!

      Geocoding API
      Maps SDK for Android
      Places API
      Geolocation API
      이렇게 사용설정을 하니 이제야 뜨네요!!!ㅠㅠㅠㅠㅠㅠ 감사합니다

      이제 프래그먼트에서 왜 null 값이 뜨는지만,, 찾으면 되겠네요... 후.....

    • thumbnail
      Favicon of https://webnautes.tistory.com BlogIcon webnautes
      2021.01.25 23:27 신고

      다행입니다

  14. thumbnail
    Favicon of https://rndtn6851.tistory.com BlogIcon syouth

    안녕하세요!! 구글 places 에 대한 정보가 없어서 구글 바다를 헤매이던 중 ㅠㅠ 덕분에 한줄기 빛을 찾은 기분입니당,,,ㅠㅠ 유용한 글 감사해요!
    혹시 places api for webservice 에 있는 place search 를 이용해서 type 별로 말고 장소 이름으로 위치를 검색할 수 있을까요??
    Type : 병원 -> 주변의 있는 모든 병원 이런 식이 아니라
    00병원 이라는 text로 해당 병원 장소 검색해서 마커 찍기 이런 식으로요!!
    이렇게도 구현 가능한지 궁금합니다..ㅠㅠ

    • thumbnail
      Favicon of https://webnautes.tistory.com BlogIcon webnautes
      2021.02.15 08:09 신고

      본 포스트에선 거리를 지정해서 주변의 특정타입을 검색하도록 되어있어서... 원하는 방식으로는 안될듯합니다.

  15. thumbnail
    Favicon of https://jae123.tistory.com BlogIcon jaejae

    좋은 글 감사합니다. 많은 도움 받고 있어요!
    위의 글을 따라하고 있는데 한가지 문제가 발생해서요 ㅠㅠㅠ
    오류없이 제대로 실행은 되지만 음식점들이 표시되지 않습니다.
    혹시 이런 경우 어떻게 해결해야하는지 알고 계시나요?
    항상 좋은 글 감사합니다!

    • thumbnail
      Favicon of https://webnautes.tistory.com BlogIcon webnautes
      2021.05.10 23:56 신고

      버튼누를시 로그캣의 로그를 확인하세요

    • thumbnail
      Favicon of https://jae123.tistory.com BlogIcon jaejae
      2021.05.11 12:11 신고

      kr.co.company.googlemapss0510 E/Places: noman.googleplaces.PlacesException: REQUEST_DENIED
      오류와 함께
      https://maps.googleapis.com/maps/api/place/nearbysearch/json?key=AIzaSyAHJWHnd48ierdUxp9NVx-GwkYd3qxHnT4&location=36.3065951,127.3408996&radius=500&type=restaurant
      문구가 뜹니다. 혹시 해결방법 아시나요?

    • thumbnail
      Favicon of https://webnautes.tistory.com BlogIcon webnautes
      2021.05.11 12:26 신고

      키발급이 잘못되었거나 이 방법이 막힌거 일 수 있습니다

    • thumbnail
      Favicon of https://webnautes.tistory.com BlogIcon webnautes
      2021.05.11 22:03 신고

      다시 해보니 잘됩니다. 인증키 부분을 다시해보세요

  16. thumbnail
    2021.05.11 12:14

    비밀댓글입니다

  17. thumbnail
    2021.05.11 12:23

    비밀댓글입니다

  18. thumbnail
    2021.05.11 12:30

    비밀댓글입니다

  19. thumbnail
    2021.06.02 03:23

    비밀댓글입니다

  20. thumbnail
    2021.06.02 03:45

    비밀댓글입니다

  21. thumbnail
    2021.09.03 01:36

    비밀댓글입니다