프로젝트/Android Project) 가장 가까운 주유소 찾기 app

가장 가까운 주유소 찾기 (3차 업데이트) 내용

roder 2023. 2. 7. 15:16

https://github.com/leeugun123/find_gas_station

 

GitHub - leeugun123/find_gas_station: find_gas

find_gas. Contribute to leeugun123/find_gas_station development by creating an account on GitHub.

github.com

 

# 3차 배포 내용 

 

1.  카카오네비 설치 페이지 

카카오 네비를 설치 하지 않았을 경우, 카카오 설치 페이지로 이동하게 만들었다. 처음부터 이렇게 만들었어야 하는데

세세한 부분을 고려하지 못하고, 카카오 네비가 설치되었다는 가정하에 만든 것이 내 실수였다.

 

또한 카카오 네비 말고, T맵 API나 네이버 지도 API를 추가로 만들려고 했지만, 이상하게 T맵 api가 작동하지 않았다.

T맵 홈페이지에서는 api 요청이 잘 들어온다고 뜸에도 불구하고, 버튼을 눌러도 아무런 반응이 나오지 않았다.

(로그를 찍었으나 에러조차도 뜨지 않음...)

 

다른 네비를 추가로 도입하는 것은 다음 업데이트때 고려하기로 하고, 일단 어쩔 수 없이 카카오 네비 api만 사용하는 것으로 마무리 지었다. 

 

근데 왜 안된거지?? 진짜??..

 

2.  거리 단위 m -> km 변경

거리를 m단위로 설정하니, 거리를 표시하는데 차지하는 공간도 크고, 보기에 있어서 불편한 점이 있었다.

km 단위로 바꾸어 사용자들에게 보여주는 것이 보기에도 편하고, 부피도 줄어들어 km로 변경하였다.

 

3.  MVVM 아키텍처 패턴 적용

장기간 주유소 어플을 지속적으로 유지보수하면서 드는 생각은 기능을 도입할때마다 메인엑티비티에 무작정 코드를 써야한다는 점이였다. 코드 양도 방대해질 뿐만 아니라 유지보수를 할때 코드를 일일히 다시 이해하고, 레트로핏 라이브러리를 적용함에 있어서 MVC 패턴으로는 한계가 있다고 판단되어 아키텍처 자체를 바꿨다.

 

보통 회사 공고에 안드로이드 기술 스택을 보면 MVVM 패턴이 필수로 들어가있는데,

그 이유에 대해 어느 정도 이해가 가게 되었다.

 

확실히 패턴을 적용하니 메인 엑티비티의 코드의 양 자체가 줄어들었고, View - viewModel - Model 등 각자 수행하는 역할이 모듈화 됨으로  유지 보수하기가 훨씬 편리해졌다.

 

그렇다고 MVC패턴이 나쁘다는 것은 아니였지만, 단기간에 어플을 만드는 것이 아닌 장기간에 어플을 유지보수 할 생각이였기 때문에 많은 시간과 노력이 들더라도 MVVM패턴을 적용하는 것이 장기간으로 보면 매우 좋은 선택이였다.

 

 

 

글씨가 좀 개판있지만, 구조를 적용하면 이런식으로 만들었다. 이게 정확한 MVVM 패턴인지는 좀 더 공부가 필요하겠지만,

그래도 각 역할을 모듈화/분업화 하니 훨씬 유지보수가 편리해졌다.

 

 

4. 레트로핏 라이브러리 사용

사실 레트로핏을 적용한 이유는 주유소 상세정보에 편의점과 세차장 유무를 사용자에게 \

편리하게 보여주기 위해 적용하였다.

 

또한 HttpClient와 요즘 레트로핏 라이브러리는의 차이점을 알고, 레트로핏의 사용방법을 익히고자 적용하였다.

사실 MVVM 패턴을 적용한 것도 레트로핏 라이브러리 보다 더 편하게 적용하기 위해 구성 한 것이다.

 

업데이트 이전에는 api를 단 한번만 호출하여, 사용자가 원하는 조건에 맞는 전체 주유소 리스트를 호출하여 리사이클러뷰에 보여주는 방식이였다면, 

 

주유소 상세 정보 즉 (이름,주소, 세차장과 편의점 유무, 전화 번호는)에 대한 정보는  한번 호출한 api 정보안에서

주유소의 uid를 매개변수로 추가적인 api를 호출하여 응답받은 주유소의 상세정보까지 합쳐 list에 저장하는 방식으로

바뀌었다..

 

이전 방식은 주유소의 전체 리스트를 한번만 호출하여 보여주는 방식이라 속도가 빨랐지만, 세차장과 편의점 유무 정보등 추가적인 상세정보도 사용자에게 보여주는 방식이라 정보를 보여주는데 좀 더 오랜 시간이 걸렸다.

 

속도적인 면에서는 이전이 더 나을수 있다는 생각이 들지만,

세차장과 편의점 유무는 사용자에게 보다 편리한 정보 인 것 같아 업데이트 하였다. 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
public class GetOilRepository {
 
    private Retrofit retrofit;
    private final static String BASE_URL = "http:///www.opinet.co.kr/";
    RetrofitAPI retrofitAPI;
    List<oil_list> moil_list;
 
    private String apiKey = BuildConfig.GAS_API_KEY;
 
    private MyRecyclerAdapter myRecyclerAdapter;
 
    String oil = "";
 
    public GetOilRepository(Application application){
        super();
 
        moil_list = new ArrayList<>();
 
        retrofit = new Retrofit.Builder()
                .baseUrl(BASE_URL)
                .addConverterFactory(GsonConverterFactory.create())
                .build();
 
        retrofitAPI = retrofit.create(RetrofitAPI.class);
 
    }
 
    public void getOilDetail(String sort, int size, RecyclerView mRecyclerView,
                              GoogleMap mMap,String uid,String name,String gas_price,String distance,String inputOil,
                             int imageResource,float getX,float getY){
 
        retrofitAPI.getOilDetail(apiKey,"json",uid)
                .enqueue(new Callback<OilDetail>() {
                    @Override
                    public void onResponse(Call<OilDetail> call, Response<OilDetail> response) {
 
                        if(response.isSuccessful()){
 
                            OilDetail oilDetail = response.body();
                            org.techtown.find_gas_station.Retrofit.oilDetail.RESULT result = oilDetail.getRESULT();
 
                            //세차장, 편의점 정보
                            String carWash = result.getOIL()[0].getCAR_WASH_YN();
                            String conStore = result.getOIL()[0].getCVS_YN();
 
                            //상세 정보 받아오기
                            String lotNumberAddress = result.getOIL()[0].getVAN_ADR();
                            String roadAddress = result.getOIL()[0].getNEW_ADR();
 
                            String tel = result.getOIL()[0].getTEL();
                            String sector = result.getOIL()[0].getLPG_YN();
 
                            int dis = (int)Double.parseDouble(distance);
                            //소수점 짜르기
 
                            moil_list.add(new oil_list(uid,name,gas_price, Integer.toString(dis),
                                    inputOil,imageResource,getX,getY,carWash,conStore,lotNumberAddress,roadAddress,
                                    tel,sector));
                            //한번 응답 받은 전체 리스트 주유소 정보와 주유소 상세정보를 포함에 리스트에 넣어준다.
 
                            //모두 받은 경우, 리사이클러 어뎁터를 호출하여 채운다.
                            if(moil_list.size() == size){
                            
                                
            
                                if(sort.equals("1")){
                                    Collections.sort(moil_list,new OilPriceComparator());
                                }//가격순
                                else{
                                    Collections.sort(moil_list,new OilDistanceComparator());
                                }//거리순
 
                                //불필요한 정렬이 생성
 
                                //데이터는 제대로 들어감.
 
                                myRecyclerAdapter = new MyRecyclerAdapter(moil_list,mMap);
                                myRecyclerAdapter.notifyDataSetChanged();
 
                                //notifyDataSetChanged() 예외처리 실험
 
                                mRecyclerView.setAdapter(myRecyclerAdapter);
 
                            }
 
                        }
 
 
 
                    }
 
                    @Override
                    public void onFailure(Call<OilDetail> call, Throwable t) {
 
                    }
                });
 
 
    }
 
    public void getOilList(
                       RecyclerView mRecyclerView,
                       GoogleMap mMap,  String xPos, String yPos, String radius, String sort, String oilKind) {
 
 
        oil = oilKind;
 
        retrofitAPI.getOilList(apiKey, "json", xPos, yPos, radius,oilKind,sort)
                .enqueue(new Callback<MyPojo>() {
 
                    @Override
                    public void onResponse(Call<MyPojo> call, Response<MyPojo> response) {
 
                        moil_list = new ArrayList<>();
                        //clear가 아닌 객체를 새로 생성
 
 
                        if(response.isSuccessful()){
 
                            MyPojo myPojo = response.body();
                            RESULT result = myPojo.getRESULT();
 
                            for(int i=0; i<result.getOIL().length; i++){
 
                               String uid = result.getOIL()[i].getUNI_ID();
                               //주유소 ID
 
                               String distance = result.getOIL()[i].getDISTANCE();
                               //주유소 거리
 
                               String name = result.getOIL()[i].getOS_NM();
                               //주유소 이름(상호명)
 
                               String gas_price = result.getOIL()[i].getPRICE();
                               //주유소 가격
 
                                //Log.e("TAG",name +" "+gas_price);
 
                               String inputOil;
 
 
                               if(oil.equals("B027")){
                                   inputOil = "휘발유";
                               }
                               else if(oil.equals("D047")){
                                   inputOil = "경유";
                               }
                               else if(oil.equals("B034")){
                                   inputOil = "고급휘발유";
                               }
                               else if(oil.equals("C004")){
                                   inputOil = "실내등유";
                               }
                               else
                                   inputOil = "자동차부탄";
 
 
                               float xPos = Float.parseFloat(result.getOIL()[i].getGIS_X_COOR());
                               //x좌표 위치
 
                               float yPos = Float.parseFloat(result.getOIL()[i].getGIS_Y_COOR());
                               //y좌표 위치
 
                                GeoTransPoint point = new GeoTransPoint(xPos,yPos);
 
                                GeoTransPoint out = GeoTrans.convert(GeoTrans.KATEC, GeoTrans.GEO,point);
                                //KATEC -> Wgs84좌표계로 변경
 
                                String trademark = result.getOIL()[i].getPOLL_DIV_CD();
                               //트레이드 마크
 
                                int imageResource;
                                //이미지 리소스
 
                                if(trademark.equals("SKE")){
                                    imageResource = R.drawable.sk;
                                }
                                else if(trademark.equals("GSC")){
                                    imageResource = R.drawable.gs;
                                }
                                else if(trademark.equals("HDO")){
                                    imageResource = R.drawable.hdoil;
                                }
                                else if(trademark.equals("SOL")){
                                    imageResource = R.drawable.so;
                                }
                                else if(trademark.equals("RTO")){
                                    imageResource = R.drawable.rto;
                                }//비슷
                                else if(trademark.equals("RTX")){
                                    imageResource = R.drawable.rto;
                                }//비슷
                                else if(trademark.equals("RTX")){
                                    imageResource = R.drawable.rto;
                                }
                                else if(trademark.equals("NHO")){
                                    imageResource = R.drawable.nho;
                                }
                                else if(trademark.equals("E1G")){
                                    imageResource = R.drawable.e1;
                                }
                                else if(trademark.equals("SKG")){
                                    imageResource = R.drawable.skgas;
                                }
                                else
                                    imageResource = R.drawable.oil_2;
 
 
 
                                getOilDetail(sort,result.getOIL().length,mRecyclerView,mMap,uid,name,gas_price,distance,inputOil,
                                imageResource,(float)out.getX(),(float)out.getY());
                                //이미 받은 응답 데이터로 주유소의 상세정보 api 호출
 
 
                            }
 
 
 
 
                }
 
    }
 
    @Override
    public void onFailure(Call<MyPojo> call, Throwable t) {
 
 
                    }
 
 
                });
 
 
 
    }
 
 
 
 
}
 
cs

 

레트로핏 라이브러리를 사용하면서 제일 어려웠던 점은 비동기로 구현하다보니 가격순,거리순으로 정렬되었던 주유소 정보가 상세정보까지 합쳐지면서 정렬이 흐트러져 리사이클러뷰에 보여지는 문제가 있었다.

 

이를 막기 위해 추가로 Collections.sort를 이용해 정렬을 하였지만, 이미 정렬되어 온 데이터를 다시 정렬하여 보여지니 시간이 더욱 길어지게 되었다. 비동기로 구현하는데 나타나는 어려움을 해결하는 것이 3차 업데이트를 하면서 처리해야 할 숙제이다.