semin****
30
2021-02-08 16:06:23
9
294

Android retrofit query 사용시 에러


안녕하세요. 안드로이드 독학하고 있는 학생입니다.

기상청의 날씨 OpenAPI를 활용해 날씨 정보를 출력하는 어플 제작을 목표로 하고 있습니다.

어제 Jaxb를 이용해 OpenApi 사용 관련 질문 올렸었는데요.

Jaxb가 더이상 지원하지 않는다는 이야기를 듣고 GsonCoverter를 이용해서 OpenAPI를 얻어오는데에 성공했습니다.

아래의 소스코드에서 getWeather을 사용하면  "expected begin_object but was string at line 1 column 1 path $" 에러가 발생합니다.

그런데 getWeather2를 사용하면 OpenAPI Json 데이터를 잘 받아오더라구요.....


RetrofitInterface.java

public interface RetrofitInterface {

    @GET("1360000/VilageFcstInfoService/getUltraSrtNcst")
    Call<Result> getWeather(@Query("serviceKey") String serviceKey,
                            @Query("pageNo") String pageNo,
                            @Query("numOfRows") String numOfRows,
                            @Query("dataType") String dataType,
                            @Query("base_date") String base_date,
                            @Query("base_time") String base_time,
                            @Query("nx") String nx,
                            @Query("ny") String ny);

    @GET("1360000/VilageFcstInfoService/getUltraSrtNcst?serviceKey=J1uWhMdL85rUtm1%2FogRUgAehBm4pAZ2QJBmZ8ytsj9q5VPkKoPyTuUWItYfi5LAXgTA%2Bmn2ERVnNZDQsfwYxpg%3D%3D&pageNo=1&numOfRows=8&dataType=JSON&base_date=20210208&base_time=1200&nx=59&ny=122")
    Call<Result> getWeather2();

}

MainActivity.java

public class MainActivity extends AppCompatActivity {
    private TextView tv_weather;

    private RetrofitClient retrofitClient;
    private RetrofitInterface retrofitInterface;

    private String MyKey = "MyServiceKey";

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

        tv_weather = (TextView)findViewById(R.id.tv_weather);
       

        try {
            retrofitClient = RetrofitClient.getInstance();
            retrofitInterface = RetrofitClient.getRetrofitInterface();
            /*
            retrofitInterface.getWeather(MyKey,
                    "1",
                    "8",
                    "JSON",
                    "20210208",
                    "1300",
                    "59",
                    "122").enqueue(new Callback<Result>() {
                @Override
                public void onResponse(Call<Result> call, retrofit2.Response<Result> response) {
                    Result result = response.body();
                    String str = "";
                    for(int i = 0; i < result.getResponse().getBody().getItems().getItem().size(); i++){
                        str += result.getResponse().getBody().getItems().getItem().get(i).getObsrValue() + "\n";
                    }
                    tv_weather.setText(str);
                }

                @Override
                public void onFailure(Call<Result> call, Throwable t) {
                    tv_weather.setText(t.getMessage());
                    t.printStackTrace();
                }
            });
            */

            retrofitInterface.getWeather2().enqueue(new Callback<Result>() {
                @Override
                public void onResponse(Call<Result> call, Response<Result> response) {
                    Result result = response.body();
                    String str = "";
                    for(int i = 0; i < result.getResponse().getBody().getItems().getItem().size(); i++){
                        str += result.getResponse().getBody().getItems().getItem().get(i).getObsrValue() + "\n";
                    }
                    tv_weather.setText(str);
                }

                @Override
                public void onFailure(Call<Result> call, Throwable t) {
                    tv_weather.setText(t.getMessage());
                    t.printStackTrace();
                }
            });
       
        }catch (Exception e){
            tv_weather.setText(e.getMessage());
        }


    }
}

RetrofitInterface.java

public interface RetrofitInterface {

    @GET("1360000/VilageFcstInfoService/getUltraSrtNcst")
    Call<Result> getWeather(@Query("serviceKey") String serviceKey,
                            @Query("pageNo") String pageNo,
                            @Query("numOfRows") String numOfRows,
                            @Query("dataType") String dataType,
                            @Query("base_date") String base_date,
                            @Query("base_time") String base_time,
                            @Query("nx") String nx,
                            @Query("ny") String ny);

    @GET("1360000/VilageFcstInfoService/getUltraSrtNcst?serviceKey=J1uWhMdL85rUtm1%2FogRUgAehBm4pAZ2QJBmZ8ytsj9q5VPkKoPyTuUWItYfi5LAXgTA%2Bmn2ERVnNZDQsfwYxpg%3D%3D&pageNo=1&numOfRows=8&dataType=JSON&base_date=20210208&base_time=1200&nx=59&ny=122")
    Call<Result> getWeather2();

}

RetrofitClient.java

public class RetrofitClient {
    private static RetrofitClient instance = null;
    private static RetrofitInterface retrofitInterface;
    private static String baseUrl = "http://apis.data.go.kr/";

    private RetrofitClient(){
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(baseUrl)
                .addConverterFactory(GsonConverterFactory.create(new GsonBuilder().setLenient().create()))
                .build();
        retrofitInterface = retrofit.create(RetrofitInterface.class);
    }

    public static RetrofitClient getInstance(){
        if(instance == null){
            instance = new RetrofitClient();
        }
        return instance;
    }

    public static RetrofitInterface getRetrofitInterface() {
        return retrofitInterface;
    }
}



제가 Query를 잘못 사용한 것인지, 아니면 뭔가 설정이 잘못된건지 아무리 찾아봐도 해결을 하지 못해서 질문을 올립니다....

0
  • 답변 9

  • p2c2kbf
    158
    2021-02-08 19:28:26

    전체 리스트를 받아오는 응답 Result는 잘 정의가 되어 있어서 결과값이 잘 받아지고

    query를 해서 받아오는 Result 객체는 어느 한 부분이 맞지 않아서 그렇습니다.

    api 페이지에 있는 응답 메세지를 잘 확인해보세요.

  • semin****
    30
    2021-02-08 19:45:45 작성 2021-02-08 20:00:21 수정됨

    답변 감사합니다.

    제가 아무리 기상청에서 제공하는 활용가이드를 찾아보고

    URL이랑 Query랑 비교해보고

    getWeather를 통해 입력한 값까지 비교해봤는데

    틀린부분을 못찾아서 그러는데.....

    혹시 제가 잘못 작성한 부분이 딱 봐도 눈에 보이시나요.....?

  • p2c2kbf
    158
    2021-02-08 21:00:14

    입력값이 문제가 아니고 서버에서 내려주는 결과값과 코드로 구현하신 Result 값의 형식이 맞지 않아서 그렇습니다.   

  • semin****
    30
    2021-02-08 21:29:37

    자꾸 귀찮게 해드려서 죄송합니다.....

    query로 만든 url과 하나의 문자열로 입력한 getWeather와 getWeather2가 같은 URL이고,

    Result도 따로 만든것이 아니라 같은 Result로 만들었습니다.

    실행했을때는 getWeather2를 주석처리하고 getWeather를 실행하거나,

    getWeather를 주석처리하고 getWeather2를 실행했습니다.

    입력값이 문제가 아니라 하셨는데 입력값이 문제가 아니라면

    Query문이 제대로 작성된 것이고 같은 URL값을 넣어준것이라 이해되는데,

    같은 URL이고, 같은 모양의 클래스를 만들었는데 형식이 맞지않아서 그럴수가 있나요...?

    Result값의 형식이 맞지 않는다는 말씀은 JSON을 받을 객체를 잘못된 형식으로 생성했다는 말인가요....?

  • p2c2kbf
    158
    2021-02-08 22:46:16

    아..getWeather2의 쿼리문이 직접 일일이 넣어주신거군요

    제가 질문을 잘못 이해했네요

    그럼 getWeather 의 쿼리가 문제가 있다고 볼 수 있네요

    혹시 pageNo가 String 타입이 맞나요? 보통은 Int로 넘겨주는데...



  • semin****
    30
    2021-02-08 23:48:59

    답변 감사합니다!!

    첨부한 사진이 기상청에서 제공하는 API요청메세지 명세입니다.

    사진에서 자료형이 나타나지는 않지만,

    제 생각으로 정수형 타입이라 생각되는 pageNo, numOfRows, nx, ny를 int 형으로 바꿔서도 해봤지만

    같은 오류메세지를 받았습니다!

  • semin****
    30
    2021-02-09 10:53:50

    혼자 이것저것 더 해봤는데, 서비스키를 쿼리문에서 빼면 제대로 동작합니다.

    근데 이게 왜 이렇게 되는건지 이해가 안되네요.....

    문자열이 너무 길면 Query로 넘겨주면서 깨질수도 있나요??


    String MyKey = Mykey
    
        @GET("1360000/VilageFcstInfoService/getUltraSrtNcst?serviceKey"+MyKey)
        Call<Result> getWeather(@Query("pageNo") int pageNo,
                                @Query("numOfRows") int numOfRows,
                                @Query("dataType") String dataType,
                                @Query("base_date") String base_date,
                                @Query("base_time") String base_time,
                                @Query("nx") int nx,
                                @Query("ny") int ny);


  • Willee21
    119
    2021-02-10 11:59:54

    serviceKey의 값을보면,

       @GET("1360000/VilageFcstInfoService/getUltraSrtNcst?serviceKey=J1uWhMdL85rUtm1%2FogRUgAehBm4pAZ2QJBmZ8ytsj9q5VPkKoPyTuUWItYfi5LAXgTA%2Bmn2ERVnNZDQsfwYxpg%3D%3D&pageNo=1&numOfRows=8&dataType=JSON&base_date=20210208&base_time=1200&nx=59&ny=122")

    %값이 들어갔죠? 이건 일반 String이 아닙니다.

    공공포탈에서 왜 그렇게 하는지 모르겠지만,

    ServiceKey를 UrlEncoded로 넣어야 정상적으로 동작하는 경우가 있습니다.

    그래서 발급받은 ServiceKey를 아래 사이트 가서

    https://www.url-encode-decode.com/

    urlEncoded로 받아서 넣거나,

    아니면, serviceKey를 상기 노란 부분으로 넣어야 정상 동작합니다. (아니면 반대로, UrlEncoded --> Normal String으로 변환해 주어야 합니다. 기억이 가물가물...)

    둘 다 시도해 보세요.

    그리고 저 키를 공개적으로 달고 문의를 하면 안되니, 다시 발급받으시길 바랍니다.

    다른 사람이 똑같이 쓸 수 있어요. (쿼리수 제약이 있습니다)

  • semin****
    30
    2021-03-16 16:41:36

    @Willee21 답변 감사합니다

    최근에 OKKY를 안들어와서 이제야 확인했네요....

    새로운 프로젝트 진행중인데 서비스키 넣을때 참고하도록 하겠습니다 :)

  • 로그인을 하시면 답변을 등록할 수 있습니다.