마스터Q&A 안드로이드는 안드로이드 개발자들의 질문과 답변을 위한 지식 커뮤니티 사이트입니다. 안드로이드펍에서 운영하고 있습니다. [사용법, 운영진]

서버에 저장한 내용을 리사이클러뷰에 업데이트하기 질문

0 추천

현재 API에서 리뷰 데이터를 받아와 앱화면에 표시해주고 있습니다.

거기에 제가 작성한 리뷰데이터를 서버(API)에 저장하고 이 저장한 데이터를 실시간으로 다시 갱신하고

싶습니다. 

즉, 동작을 간단하게 적어보자면 현재 리뷰 코멘트들은

1. readComment라는 API 서버에서 불러오고 있습니다.

2.작성하기를 통해 작성한 리뷰는 createComment라는 서버에 양식?에 맞춰 보냅니다.

여기 보낸 리뷰들은 readComment 서버에 json형식으로 표시됩니다.

3. 서버는 volley를 사용하고 데이터를 불러올때는 json을 gson으로 파싱해 아이템에 세팅합니다.

 

이 리뷰가 보이는 화면에서 리뷰는 현재 API 서버에 요청해 저장된 리뷰들을 받아온것입니다.

리뷰는 리사이클러뷰로 되어있습니다.

여기서 작성하기 버튼을 누르면 

리뷰작성화면으로 이동하게되는데, 리뷰를 저장하면 이전 화면에서 실시간으로 아이템을 업데이트 하고 싶습니다

저장버튼을 누르면 이제 데이터를 전송을해야하는데, 어떻게 업데이트 시킬지 2~3가지 방법을 생각

했습니다.

1.작성하기 화면을 띄울때 startActivityForReseult()를 사용해서 작성하기 액티비티가 종료 될때, intent에 작성된 내용과, 평점등을 따로 저장해 호출한 액티비티로 보내 거기서 아이템에 받은 데이터들을 세팅후 리사이클러뷰 아이템에 추가한후 notifyDatasetChanged() 한다. 물론 데이터는 서버쪽으로 보내지고 다음번에 새로 시작하면 작성한 리뷰가 추가되어 화면에 보인다.

2.마찬가지로 startActivityForResult()를 사용하지만 onActivityResult()에서 다시 서버를 요청하고 데이터를 파싱하는 함수를 호출해서 데이터를 세팅한다...

 

두가지 방법을 생각했지만 1번의 경우 API를 이용해서 세팅한다는 취지와는 좀 거리가 먼것같아 

일단은 2번을 사용했는데요..2번을해도 데이터,,그러니까 아이템이 갱신되지 않습니다..어떤점에 문제일까요?

 

한줄평 목록을 받아오는 코드입니다.

// 서버요청(요청객체만들기) 및 한줄평 목록 받아오기
    public void requestCommentList(final int curPos) {
        String url = "http://" + AppHelper.host + ":"+ AppHelper.port + "/movie/readCommentList";
        url += "?" + "id=" + curPos + "&startindex=1&length=10"; // 요청 파라미터, 현재 페이지에 따른 api 부르기
        
        StringRequest request = new StringRequest(
                Request.Method.GET,
                url,
                new Response.Listener<String>() {
                    @Override
                    public void onResponse(String response) {
                        // 요청 보내고 정상 응답을 받는곳
                        parsingCommentModel(response, curPos); // gson으로 파싱하기
                        println("통신성공 in requestCommentList: " + response);
                    }
                },
                new Response.ErrorListener() {
                    @Override
                    public void onErrorResponse(VolleyError error) {
                        println("에러 발생 in requestCommentList: " + error );
                    }
                }
        );
        request.setShouldCache(false);
        AppHelper.requestQueue.add(request); // 요청큐에 요청객체 넣기
    }

 

파싱하는 함수입니다.

// 받아온 CommentList 응답 gson으로 자바 객체화(파싱) 후 레이아웃에 셋팅
    public void parsingCommentModel(String response, int curPos) {
        Gson gson = new Gson();
        
        ResponseInfo info = gson.fromJson(response, ResponseInfo.class);
        if(info.code == 200) {
            cmArray = gson.fromJson(response, CommentModelArray.class);
            for(int i=0; i<cmArray.result.size(); i++) {
                items.add(cmArray.result.get(i)); // gson으로 파싱된 객체배열을 하나씩 꺼내 items에 넣기
            }
            ShowOnlyTwoItems();
            recyclerView.setAdapter(adapter);
            adapter.notifyDataSetChanged();
        }
    }

 

작성한 한줄평을 받아오는 onActivityResult() 입니다.

// 작성한 한줄평 데이터 받아와서 추가하기
    @Override
    public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if(requestCode == 101) { // 상세보기의 작성하기에서 온 데이터
            if(data != null) {
                Log.d("onActivityResult", "requestCode : 101");
                requestCommentList(curPos); // 다시 서버 호출해서 데이터 세팅하기
            }
        }
    }

 

작성하고 저장하기 코드입니다.

// 한줄평 저장하기
        save.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                String check = write.getText().toString();
                // 아무것도 입력하지 않았을때
                if (check.equals("")) {
                    Toast.makeText(getApplicationContext(), "내용을 입력해주세요", Toast.LENGTH_LONG).show();
                }
                // 내용 저장할때
                else {
                    saveWriteCommentData(id);
                    final Snackbar sb = Snackbar.make(wc, "저장 완료", Snackbar.LENGTH_INDEFINITE).setDuration(5000);
                    // 스낵바가 올라오고 사라진걸 알수 있는 콜백함수
                    sb.addCallback(new Snackbar.Callback() {
                        @Override
                        public void onShown(Snackbar sb) {
                            super.onShown(sb);
                        }

                        @Override
                        public void onDismissed(Snackbar transientBottomBar, int event) {
                            finish();
                        }
                    });
                    sb.show();

                }
            }
        });

 

작성한 내용을 createComment 서버에 저장 및 호출한 액티비티에 intent보내는 코드입니다.

// 서버요청(요청객체만들기) 및 한줄평 서버에 저장하기 (POST 방식)
    public void saveWriteCommentData(final int curPos) {
        
        String url = "http://" + AppHelper.host + ":"+ AppHelper.port + "/movie/createComment";

        StringRequest request = new StringRequest(
                Request.Method.POST,
                url,
                new Response.Listener<String>() {
                    @Override
                    public void onResponse(String response) {
                        Gson gson = new Gson();
                        ResponseInfo info = gson.fromJson(response, ResponseInfo.class);
                        if(info.code == 400) {
                            Log.d("saveWriteCommentData", "호출확인 ");
                            Intent intent = new Intent();
                            intent.putExtra("Infocode", Integer.toString(400)); // 별의미없는 보냄확인용 코드
                            setResult(RESULT_OK, intent);
                        }
                    }
                },
                new Response.ErrorListener() {
                    @Override
                    public void onErrorResponse(VolleyError error) {

                    }
                }
        ) {
            // createComment에 보내면 readComment에 표시됨
            @Override
            protected Map<String, String> getParams() throws AuthFailureError {
                Map<String, String> params = new HashMap<>();
                f_rating = rating.getRating();
                params.put("id", Integer.toString(curPos));
                params.put("writer", "안드슬레이브");
                params.put("rating", f_rating.toString());
                params.put("contents", write.getText().toString());

                Log.d("getParams() in WC.java", "getParams 호출확인 ");
                return params;
            }
        };

        request.setShouldCache(false);
        AppHelper.requestQueue.add(request); // 요청큐에 요청객체 넣기
    }

 

조금 긴것같지만 좀 도와주시면 감사하겠습니다..

저는 저장한 내용을 서버에 보내고 다시 서버를 요청하고 호출하고 리사이클러뷰의

notifyDatasetChanged를 호출하면 갱신될것같았지만 아무런 반응이 없네요..ㅜㅜ

로그를 찍어보니 호출될건 다 호출되는것 같은데..뭐가문제일까요?ㅜ

 

그리고 제가하는 방법..그러니까 서버를 다시요청하고 다시 api를 받아와 앱의 화면을 갱신하는 방법이

괜찮은 방법인가요?

codeslave (3,940 포인트) 님이 2020년 11월 17일 질문

1개의 답변

0 추천
 
채택된 답변

서버에 포스팅하는 액티비티에서 입력값 검사, 서버 요청, 에러처리를 해주는 게 맞습니다. 그래야 역할도 분리되고 User experience가 더 자연스러워집니다. 예를 들면 서버 요청 후,응답값이 에러이면 같은 화면에서 에러메세지를 보여준 후 다시 시도 하도록 해주어야 겠죠.

그리고 서버에 데이터 변경사항이 생긴 것을 안다면 당연히 데이터 갱신해 주어야겠죠. 이것도 맞게 하신 거라고 봅니다. 그리고 화면 갱신 관련해서는 parsingCommentModel 메소드가 저장 전에도 잘 동작하는 경우라면 서버에 저장하는 부분이 잘못이거나 포스팅하는 액티비티가 종료될 때 setActivity에 결과값을 제대로 세팅하지 않았거나 받는 쪽에서 잘못 받는 문제일 것 같습니다.
디버깅을 해보시고 서버에 데이터는 정확하게 저장이 되는지, 저장 후에 데이터 갱신시에 값은 제대로 오는지, 포스팅 액티비티에서 돌아올 때  값은 제대로 전달이 되는지.

if(requestCode == 101) { // 상세보기의 작성하기에서 온 데이터
            if(data != null) {
                Log.d("onActivityResult", "requestCode : 101");
                requestCommentList(curPos); // 다시 서버 호출해서 데이터 세팅하기
            }
        }

개인적으로는 위의 코드가 의심이 되긴합니다. 왜냐하면 포스팅하는 액티비티에서 setResult를 통해 번들을 리턴하는 부분이 안보이거든요. 그리고 data는 사용하지 않으실 것 같은데 굳이 왜 체크를 하시는지 궁금하네요.  그냥 requestCode와 resultCode만 체크하셔도 될 것 같아 보이거든요.

그리고 아래의 메소드 말인데요,

// 받아온 CommentList 응답 gson으로 자바 객체화(파싱) 후 레이아웃에 셋팅
public void parsingCommentModel(String response, int curPos) {
}

주석이랑 실제로 하는일이 다르네요. 주석과 메소드 이름만 보면 응답내용을 파싱한다고 되어 있는데 실제로는 parseAndUpdateReview 네요. 메소드를 parse와 update하는 두개로 분리하시던가, 메소드  이름을 바꾸시던가 하는게 좋을 것것 같아요. 그리고 코멘트의 내용과 메소드의 이름이 다른 게 없기 때문에, 이런 코멘트를 전혀 도움이 안되는 코멘트예요. 오히려 코드 읽기를 방해할 수 있죠. 이런 코멘트는 삭제하기를 권장드려요.

spark (226,420 포인트) 님이 2020년 11월 17일 답변
codeslave님이 2020년 11월 18일 채택됨
휴...감사합니다 해결했습니다!
함수는 호출되는데 이상하여 선생님 조언대로 디버깅을 차례차례 따라가며 해보았습니다..확인결과 일단 서버에서 값은 제대로 불러오기는 합니다만,
제가 items를 멤버 변수로 선언하였더니 맨처음 api에서 데이터를 가져와
ArrayList 즉 items에 저장을하는데..이후에 리뷰 작성후에 다시 api에서 데이터를 가져와 추가를 하는데 items.add를 하다보니 제일 끝으로 가는거였습니다..
디버깅을하여 값을 하나하나 까보니 알게되었네요..
그러니까 ..처음에 10개의 리뷰를 받고 items.add했다고 치면 이후에 작성후에 api를 받으면 11개의 리뷰를 받고 items.add 를하니 이 items에는 총 21개의 리뷰가 저장되었던거네요
저는 앱에서 지금 현재 10개의 리뷰만 보이게 해놨더니 당연 뒤에껀 안보였네요.
그리고 이 문제는 멤버변수로 선언되어있던 items를 api에서 데이터를 불러오고 파싱하는 함수내에 선언하여 호출될때마다 새로운 객체로 초기화 되도록하여 해결했습니다..
또 조언해주신 parsing 메소드 이름도 parsingAndUpdateComment로 바꾸었습니다.
주석같은경우에는 아직 제가 초보자다이다보니까 다음에 보고 안잊어먹으려고 설명을 일단 다 달고보니 그렇게 되었네요
감사합니다!
Great job!!!
...