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

안드로이드 스튜디오에서 volley기능으로 회원가입

0 추천

안녕하세요. Volley기능을 사용하여 앱과 내부서버를 연동하여 회원정보를 데이테베이스에 저장하는 것을 목표로 진행 중 입니다.


public class FragmentRegister extends Fragment {
    private EditText et_id, et_pw;
    private Button btn_register;
    private Context context;
    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, @Nullable Bundle savedInstanceState) {
        ViewGroup rootView = (ViewGroup) inflater.inflate(R.layout.fragment_register, container, false);
        et_id = rootView.findViewById(R.id.et_id);
        et_pw = rootView.findViewById(R.id.et_pw);
        btn_register = rootView.findViewById(R.id.btn_register);
        context = container.getContext();
        // 회원가입 버튼 클릭 시 수행
        btn_register.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // EditText에 현재 입력되어 있는 값을 get(가져온다)해온다.
                String userID = et_id.getText().toString();
                String userPassword = et_pw.getText().toString();
                Response.Listener<String> responseListener = new Response.Listener<String>() {
                    @Override
                    public void onResponse(String response) {
                        try {
                            JSONObject jsonObject = new JSONObject(response);
                            boolean success = jsonObject.getBoolean("success");
                            if(success){ // 회원등록에 성공한 경우
                                Toast.makeText(getContext(), "회원등록에 성공하였습니다.", Toast.LENGTH_SHORT).show();
                                ((MainActivity)getActivity()).onChangetoLogin(); //로그인프레그먼트로 이동
                            }else {  // 회원등록에 실패한 경우
                                Toast.makeText(getContext(), "회원등록에 실패하였습니다.", Toast.LENGTH_SHORT).show();
                            }
                        } catch (JSONException e) {
                            e.printStackTrace();
                        }

                    }
                };
                RegisterRequest registerRequest = new RegisterRequest(userID, userPassword, responseListener);
                RequestQueue queue = Volley.newRequestQueue(context);
                queue.add(registerRequest);
            }
        });
        return rootView;
    }
}


아이디와 비밀번호만을 이용하여 프레그먼트에서 회원가입을 진행하고 성공 시 회원가입프레그먼트에서 로그인프레그먼트로 이동하게 코드를 짰습니다. 하지만, 실제 앱을 실행 후 버튼을 누르면 아무 동작도 하지 안않으며 회원 등록 성공여부 문구도 뜨지 않습니다.


public class RegisterRequest extends StringRequest {
    // 서버 URL 설정 (PHP 파일 연동)
    private final static String URL = "URL";

    private Map<String, String> map;
    public RegisterRequest(String userID, String userPassword, Response.Listener<String> listener){
        super(Method.POST, URL, listener, null);

        map = new HashMap<>();
        map.put("userID", userID);
        map.put("userPassword", userPassword);
    }

    @Override
    protected Map<String, String> getParams() throws AuthFailureError{
        return map;
    }

}

실제 URL 부분을 URL로 수정했습니다. 

ptsd1234 (160 포인트) 님이 6월 3일 질문

1개의 답변

+1 추천
 
채택된 답변

먼저 등록버튼을 눌렀을 때 서버의 API가 호출되는지부터 확인해 보세요. PostMan같은 툴을 이용하면 쉽게 서버의 API가 정상적으로 호출되는 상태인지 아닌지 체크하실 수 있습니다. 만약 PostMan으로 API가 호출된다면 안드로이드 앱의 문제일테지만, API가 자체가 호출되지 않는다면, 서버의 문제이기 때문에 서버가 먼저 수정되어야 겠죠.

그리고 앱의 문제라면 volley로그에 어떻게 API 요청이 전송되는지 확인해 보세요. 서버에서 원하는 형태대로 전송이 되고 있는지 확인해 보세요.

추가적으로 님이 올리신 소스코드를 보면 onCreateView가 하는 일이 너무 많습니다. onCreateView라는 메소드 이름만을 보시면, 이 메소드는 프레그먼트에서 사용하는 root 뷰를 생성하는 메소드란 걸 아실 수 있습니다. 하지만 님의 코드는 실제로 하는 이링 너무 많기 때문에  onCreateView는 잘못된 메소드입니다. 즉, 코드가 적절한 메소드나 클래스로 분리되어야 합니다. 

모바일에서는  서버 API 호출같은 네트워킹 작업은 Fragment 같은 뷰에서 하지 않고 별도의 처리 클래스를 두고 백그라운드에 처리하도록 하는게 지극히 일반적인 패턴입니다. 쓰레드 작업은 Volley가 기본적으로 처리하고 있기 때문이 크게 신경쓰지 않아도 될듯합니다. 아래 처럼 코드를 하는 일에 따라 분리해서 사용하세요.

public class MemberRegistrationResult {
    private final boolean success;

    public MemberRegistrationResult(boolean success) {
       this.success = success;
   }

   public boolean isSuccess() {
        return this.successs;
   }
}


public class RegisterMemberUseCase {

      public interface Listener {
            void onSuccess();
            void onError(Exception e);
      }

      @Nullable
      private RegisterMemberUseCase.Listener listener;
      public void setListener(RegisterMemberUseCase.Listener listener) {
           this.listener = listener;
      }
       
      public void register(String userId, String password) {
             Response.Listener<String> responseListener = new Response.Listener<String>() {
                    @Override
                    public void onResponse(String response) {
                        try {
                           // 빠르고 쉽고 더 정확한 Json 파싱을 위해 Gson 사용 
                           MemberRegistrationResult registrationResult = Gson().fromJson(response, MemberRegistrationResult.class);
                            
                           // 회원등록에 성공한 경우
                            if(registrationResult.isSuccess()){ 
                               if (listener != null) {
                                   listener.onSuccess();
                               }
                            }else {  // 회원등록에 실패한 경우
                                 if (listener != null) {
                                   listener.onError();
                                 }
                            }
                        } catch (JSONException e) {
                             if (listener != null) {
                                   listener.onError(e);
                             }
                        }

                    }
                };

                RegisterRequest registerRequest = new RegisterRequest(userId, password, responseListener);
                RequestQueue queue = Volley.newRequestQueue(context);
                queue.add(registerRequest);
            }
      }    
}


interface Navigatable {
    void onChangetoLogin()
}


public class MainActivity extends AppCompatActivity implements Navigatable {
     

      @Override
      public void onChangetoLogin() {
           ....
      }
}


public class FragmentRegister extends Fragment {
    private EditText et_id, et_pw;
    private Button btn_register;

    private RegisterMemberUseCase usecase;

    private Navigatable navigator;

    @Override
    public void onAttach (Context context) {
         super.onAttach(context);
         if (!(context instanceof Navigatable)  throw IllegalStateException("Must implment Navigatable");
         navigator = (Navigatable) context;
    }

    @Override
     public void onCreate(...) {
         super.onCreate(...)

          usecase = new RegisterMemberUseCase();
           
     }

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, @Nullable Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_register, container, false);
    }

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        et_id = view.findViewById(R.id.et_id);
        et_pw = view.findViewById(R.id.et_pw);
        btn_register = view.findViewById(R.id.btn_register);

        setupRegisterMembership();
    }

     @Override
  public void onStart() {
      super.onStart();
      useCase.setListener(this);
  }
  
  @Override
  public void onStop() {
      useCase.setListener(null);
      super.onStop();
  }
   
   private void setupRegisterMembership() {
         // 회원가입 버튼 클릭 시 수행
        btn_register.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                 useCase.register(userId(), userPassword());
            }
        });

   }

   @Override 
   public onSuccess() {
          Toast.makeText(requireContext(), "회원등록에 성공하였습니다.", Toast.LENGTH_SHORT).show();
          navigator.onChangetoLogin(); //로그인프레그먼트로 이동
   }
    
    @Override
     public void onError() {
          Toast.makeText(requireContext(), "회원등록에 실패하였습니다.", Toast.LENGTH_SHORT).show();
     }

  // EditText에 현재 입력되어 있는 값을 가져온다.
  private String userId() {
     return et_id.getText().toString();
  }

  private String userPassword() {
       return et_pw.getText().toString();
  }

 

spark (58,180 포인트) 님이 6월 3일 답변
ptsd1234님이 6월 4일 채택됨
말해주신 postman을 이용해서 php파일이 있는 URL을 입력했더니 {"success":true}가 나왔습니다. 다만, 닷홈에 데이터베이스에는 입력한 값들이 저장되지 않았는데 php파일 문제일까요?

또, 안드로이드 스튜디오에서 logcat에 다른작업은 찍히는데 회원가입 프레그먼트에서 회원가입 버튼을 눌렀을 때 아무것도 안찍힙니다.
그럼, 이제 브레이크 포인트를 찍으시고 디버거로 해당 코드가 실행이 되는지 확인해 보세요. 아무 것도 실행되지 않는다면, Volley로 request를 보내는 부분에 이상이 있는 거구요. 서버로 전송을 하고 있다면 서버에 보내는 요청 포맷 등에 문제가 있을 수 있는 거겠죠.
전 Retrofit을 주로 사용하고 Volley는 사용한 적이 없어서 Volley 코드에 대해서는 말씀드릴 수가 없네요.
해결됐습니다. 답변 달아주셔서 정말 감사합니다. 좋은 일만 가득하셨으면 좋겠습니다.
...