티스토리 뷰
Volley
원래 Volley로 만들어뒀던 통신을 Retrofit으로 갈아엎느라 진짜 일주일 내내 똥 쌌습니다.
사실 회처럼 날로 먹으려고 제대로 안 읽고 갖다붙이기만 하다가
, 멘탈 나가서
수많은 블로그 글들, Stack Overflow 반복해서 읽다보니 아주 얄팍한 깨달음이 왔고 금새 끝낼 수 있었습니다.
이걸 몰라서 그 많은 시간을 허공에 흩뿌렸나 싶더라구요... :sweat:
Volley를 사용한 기존 통신은
- BaseFrag에 기본 request 메소드를 작성해놓고
- view로 보여지는 fragment에서 이를 상속받아 사용하고,
- 해당 fragment에서
successListener
로 adapter와 연결된 arr에 데이터를 추가하는 방식이었습니다.
처음 만들었을 땐 코드량을 획기적으로 줄였다면서 너무 행복했었습니다만...
Retrofit 공부를 위한 희생양이 되었습니다. 즐거웠다 ㅠ
SearchFrag
private void requestPname(){ //입력값이 장소 이름일 때 출력
Log.d("chk", "장소 리스트 이름 requestPname: start");
final String pname = search;
params.clear();
params.put("pname", search);
request("PlaceListName.do", successListener);
//어댑터에 적용
initRecyclerView();
}
private void requestPlocation(){ //입력값이 장소 지역일 때 출력
Log.d("chk", "장소 리스트 지역 requestPlocation: start");
final String plocation = search;
params.clear();
params.put("plocation", search);
request("PlaceListLocation.do", successListener);
//어댑터에 적용
initRecyclerView();
}
private void requestPaddress(){//입력값이 장소 주소일 때 출력
Log.d("chk", "주소 리스트 지역 requestPaddress: start");
final String paddress = search;
params.clear();
params.put("paddress", search);
request("PlaceListAddress.do", successListener);
//어댑터에 적용
initRecyclerView();
}
private void requestForData() { //입력값 없이 전체 출력
//상속받은 부분
Log.d("chk", "장소 리스트 전체 requestForData: start");
params.clear();
request("PlaceList.do", successListener);
//어댑터에 적용
initRecyclerView();
}
Response.Listener<String> successListener = new Response.Listener<String>() {
//가져온 jsonArray arr에 추가
@Override
public void onResponse(String response) {
try {
JSONArray proArr = new JSONArray(response);
Log.d("proArr", "onResponse:" + response);
for (int i = 0; i < proArr.length(); i++) { //10보다 작은데 <10 해놓으니까 오류나지 멍청이 똥멍청이야!!!
JSONObject proObj = proArr.getJSONObject(i);
String pidx = proObj.getString("pidx");
String pname = proObj.getString("pname");
String pimage1 = proObj.getString("pimage1");
String pvisit = proObj.getString("pvisit");
String picon = proObj.getString("picon");
String pcategory = proObj.getString("pcategory");
String pphone = proObj.getString("pphone");
String pcontent = proObj.getString("pcontent");
//리스트에 보여줄 어레이에 추가
arr.add(i, new ItemData(pidx, pname, pimage1, pvisit, picon, pcategory, pphone, pcontent, "0"));
Log.d("chk1", "arr:" + arr.get(i).pName);
}
//데이터가 바꼈으니까 여기서 arr 변화를 notifychange해준다!
adapter.notifyDataSetChanged();
total=arr.size();
tv_tit.setText(total+"개의 결과가 있습니다");
} catch (JSONException e) {
e.printStackTrace();
}
}
};
BaseFrag
public class BaseFrag extends Fragment {
//Volley
Map<String, String> params = new HashMap<String, String>();
public BaseFrag() {
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
return super.onCreateView(inflater, container, savedInstanceState);
}
//Volley
public void request(String url, Response.Listener<String> successListener){
RequestQueue stringRequest = Volley.newRequestQueue(getActivity());
url = Storage.HOME_URL+":8180/oop/" + url;
StringRequest myReq = new StringRequest(Request.Method.POST, url,
successListener, errorListener){
@Override
protected Map<String, String> getParams() throws AuthFailureError {
String str ="str";
params.put("test",str);
return params;
}
};
myReq.setRetryPolicy(new DefaultRetryPolicy(3000, 0, 1f)
);
stringRequest.add(myReq);
}
Response.ErrorListener errorListener = new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
Log.d("ErrorResponse", "통신 실패");
}
};
}
Retrofit2
JSP로 만든 해당 서버의 서비스 파일을 doPOST로 설정해뒀기 때문에 get 메소드를 활용할 수 없었습니다.
아쉽지만 post라도 열심히 써봅니다.
ResponseGet
응답받을 JSON 데이터를 가지고
https://www.jsonschema2pojo.org/
에서 클래스를 만들어주면 다음과 같이 어노테이션을 예쁘게 달고 나옵니다.
public class ResponseGet {
@SerializedName("pimage1")
@Expose
private String pimage1;
@SerializedName("picon")
@Expose
private Object picon;
@SerializedName("pcontent")
@Expose
private String pcontent;
@SerializedName("pvisit")
@Expose
private String pvisit;
@SerializedName("pphone")
@Expose
private String pphone;
@SerializedName("plocation")
@Expose
private Integer plocation;
@SerializedName("pname")
@Expose
private String pname;
@SerializedName("pidx")
@Expose
private Integer pidx;
@SerializedName("pcategory")
@Expose
private Integer pcategory;
@SerializedName("paddress")
@Expose
private String paddress;
public String getPimage1() {
return pimage1;
}
public void setPimage1(String pimage1) {
this.pimage1 = pimage1;
}
public Object getPicon() {
return picon;
}
public void setPicon(Object picon) {
this.picon = picon;
}
public String getPcontent() {
return pcontent;
}
public void setPcontent(String pcontent) {
this.pcontent = pcontent;
}
public String getPvisit() {
return pvisit;
}
public void setPvisit(String pvisit) {
this.pvisit = pvisit;
}
public String getPphone() {
return pphone;
}
public void setPphone(String pphone) {
this.pphone = pphone;
}
public Integer getPlocation() {
return plocation;
}
public void setPlocation(Integer plocation) {
this.plocation = plocation;
}
public String getPname() {
return pname;
}
public void setPname(String pname) {
this.pname = pname;
}
public Integer getPidx() {
return pidx;
}
public void setPidx(Integer pidx) {
this.pidx = pidx;
}
public Integer getPcategory() {
return pcategory;
}
public void setPcategory(Integer pcategory) {
this.pcategory = pcategory;
}
public String getPaddress() {
return paddress;
}
public void setPaddress(String paddress) {
this.paddress = paddress;
}
}
RetroBaseApiService
public interface RetroBaseApiService {
@POST("PlaceList.do")
Call<List<ResponseGet>> rPlaceList();
@FormUrlEncoded
@POST("PlaceListLocation.do")
Call<List<ResponseGet>> rPlocation(@FieldMap HashMap<String, String> parameters);
@POST("PlaceListName.do")
Call<List<ResponseGet>> rPname(@FieldMap HashMap<String, String> parameters);
@POST("PlaceListAddress.do")
Call<List<ResponseGet>> rPaddress(@FieldMap HashMap<String, String> parameters);
}
통신에 필요한 apiService 인터페이스를 작성해줍니다. 저의 경우는 받아오는 JSON이 List 형태였기 때문에 ``Call<List>``으로 했습니다. JSON의 형태에 따라 다르게 작성해주시면 됩니다.
@POST("BASE_URL을 제외한 나머지 주소")
@FormUrlEncoded
: 파라미터를 추가할 때 넣어줍니다.
@FieldMap
: 요구되는 파라미터의 형태를 작성해주면 됩니다.
RetroClient
public class RetroClient {
public static final String BASE_URL = Storage.HOME_URL + ":8180/oop/";
private static RetroBaseApiService retroBaseApiService =null;
public static RetroBaseApiService getRetroBaseApiService(){
if(retroBaseApiService == null){
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
retroBaseApiService = retrofit.create(RetroBaseApiService.class);
}
Log.d("retrofit", "getRetroBaseApiService: returned");
return retroBaseApiService;
}
}
SearchFrag (view단)
...
public void requestRlocation(String type, String search, ArrayList<ItemData> arr){
HashMap<String, String> params2 = new HashMap<>();
params2.put(type, search);
RetroClient.getRetroBaseApiService().rPlocation(params2).enqueue(new Callback<List<ResponseGet>>() {
@Override
public void onResponse(Call<List<ResponseGet>> call, retrofit2.Response<List<ResponseGet>> response) {
List<ResponseGet> result = response.body();
Log.d("retrofit", "onResponse: success1" + result); //200 정상통신
for(int i = 0; i<result.size(); i++){
String pidx = String.valueOf(result.get(i).getPidx());
String pname = result.get(i).getPname();
String pimage1 = result.get(i).getPimage1();
String pvisit = result.get(i).getPvisit();
String picon = (String) result.get(i).getPicon();
String pcategory = String.valueOf(result.get(i).getPcategory());
String pphone = result.get(i).getPphone();
String pcontent = result.get(i).getPcontent();
arr.add(i, new ItemData(pidx, pname, pimage1, pvisit, picon, pcategory, pphone, pcontent, "0"));
Log.d("retrofit", "arr:" + arr.get(i).getpName());
}
adapter.notifyDataSetChanged();
total=arr.size();
tv_tit.setText(total+"개의 결과가 있습니다");
}
@Override
public void onFailure(Call<List<ResponseGet>> call, Throwable t) {
Log.d("retrofit", "onResponse: failed");
}
});
initRecyclerView();
}
전체적인 구조는 Volley에서와 유사합니다 (사실 그만 뜯어고치고 싶었어요. 그래서 dto로 사용한 arr 그대로 썼습니다)
통신 요청 보내고 받아온 Response는 adapter와 연결된 arr에 잘 넣어주고, 마지막으로 initRecyclerView();
메소드로 RecyclerView와 연결해줍니다.
덧붙여서
- 새로운 라이브러리라는 부담감 때문이었는지, 멀쩡하게 객체들 들어오고 있었는데, toString으로 확인이 안된다며 패닉상태에 빠졌습니다.
- 하지만 그렇다고 해도 Stack Overflow에서 말하던 toString()이 아닌 string() 메서드로 원시데이터 확인하는 법은 아직도 모르겠습니다.
- 왜 나한테만 없는거지 string() 메소드...?
열심히 통신하고 있던 레트로핏 맴도 몰라주고... 객체 숫자 세어보니 열심히 response가지고 오고 있었더라구요... 머씈...코씈...
'ANDROID' 카테고리의 다른 글
뷰 결합으로 findViewById와 작별하기🖐 (0) | 2021.04.16 |
---|---|
RecyclerView 스크롤다운시 아이템 간격 벌어짐 현상 (0) | 2021.04.13 |
null object reference 오류 (0) | 2021.03.25 |
OnClickListener에서 intent (0) | 2021.03.19 |
dependency추가해서 아이디/비밀번호 input 예쁘게! (0) | 2021.03.11 |