- Retrofit2로 서버와 통신하기
- 로그인, 회원가입 통신 구현하기
👇회원가입, 로그인 서버 통신
-
ServiceCreator - Retrofit Interface 구현체
object ServiceCreator { private const val BASE_URL = "http://cherishserver.com" private val retrofit: Retrofit = Retrofit.Builder() .baseUrl(BASE_URL) .addConverterFactory(GsonConverterFactory.create()) .build() val loginService: LoginService = retrofit.create(LoginService::class.java) }
-
LoginService : 서버 요청 동작
interface LoginService { @POST("/login/signin") fun postLogin( @Body body: RequestLoginData ) : Call<ResponseLoginData> @POST("/login/signup") fun postSignUp( @Body body: RequestSignUpData ) : Call<ResponseSignUpData> }
-
서버 Request, Response 객체 설계
//RequestLoginData.kt data class RequestLoginData ( @SerializedName("email") val id: String, val password: String, ) //RequestSignUpData.kt data class RequestSignUpData ( @SerializedName("email") val id: String, val password: String, val sex: String, val nickname: String, val phone: String, val birth: String, ) //ResponLoginData.kt data class ResponseLoginData ( @SerializedName("email") val id: String, val password: String, val data: LoginData? ) data class LoginData( @SerializedName("UserId") val userId: Int, val user_nickname: String, val token: String ) //ResponSignUpData.kt data class ResponseSignUpData ( @SerializedName("email") val id: String, val password: String, val sex: String, val nickname: String, val phone: String, val birth: String, val data: SignUpData? ) data class SignUpData( val nickname: String )
-
통신 요청 - SignInActivity.kt : 로그인 버튼 클릭 시 빈칸이 없다면 서버 요청
private fun loginButtonClickEvent() { binding.btnLogin.setOnClickListener { val userId = binding.etLoginId.text val userPw = binding.etLoginPw.text if (userId.isNullOrBlank() || userPw.isNullOrBlank()) { Toast.makeText(this@SignInActivity, "아이디/비밀번호를 확인해주세요!", Toast.LENGTH_SHORT) .show() } else { loginCommunicateServer() } } } private fun loginCommunicateServer(){ //서버로 보낼 로그인 데이터 생성 val requestLoginData = RequestLoginData( id = binding.etLoginId.text.toString(), password = binding.etLoginPw.text.toString() ) val call: Call<ResponseLoginData> = ServiceCreator.loginService.postLogin((requestLoginData)) call.enqueue(object: Callback<ResponseLoginData> { override fun onResponse( call: Call<ResponseLoginData>, response: Response<ResponseLoginData> ) { if(response.isSuccessful){ val data = response.body()?.data Toast.makeText(this@SignInActivity, "로그인 성공 \n userNickname : "+data?.user_nickname, Toast.LENGTH_SHORT).show() startHomeActivity() }else{ //에러났을 때 코드 Toast.makeText(this@SignInActivity, "로그인 실패", Toast.LENGTH_SHORT).show() } } override fun onFailure(call: Call<ResponseLoginData>, t: Throwable) { Log.d("NetworkTestSignIn","error:$t") } }) }
통신 요청 - SignUpActivity.kt : 회원가입 버튼 클릭 시 빈칸이 없다면 서버 요청
private fun signUpButtonClickEvent() { binding.btnSignUp.setOnClickListener { ... } else { signUpCommunicateServer() val intent = Intent(this@SignUpActivity, HomeActivity::class.java) intent.putExtra("userName", userName.toString()) .putExtra("userId", userId.toString()) .putExtra("userPw", userPw.toString()) setResult( RESULT_OK, intent ) finish() } } } private fun signUpCommunicateServer(){ //서버로 보낼 회원가입 데이터 생성 val requestSignUpData = RequestSignUpData( id = binding.etSignupId.text.toString(), password = binding.etSignupPw.text.toString(), sex = "0", nickname = binding.etSignupName.text.toString(), phone = "010-0000-0000", birth = "1999-00-00" ) val call: Call<ResponseSignUpData> = ServiceCreator.loginService.postSignUp((requestSignUpData)) call.enqueue(object: Callback<ResponseSignUpData> { override fun onResponse( call: Call<ResponseSignUpData>, response: Response<ResponseSignUpData> ) { if(response.isSuccessful){ val data = response.body()?.data Toast.makeText(this@SignUpActivity, "회원가입 성공 \n 이름 : "+data?.nickname, Toast.LENGTH_SHORT).show() }else{ //에러났을 때 코드 Toast.makeText(this@SignUpActivity, "회원가입 실패", Toast.LENGTH_SHORT).show() } } override fun onFailure(call: Call<ResponseSignUpData>, t: Throwable) { Log.d("NetworkTestSignUp","error:$t") } }) }
-
retrofit2 을 이용한 서버 통신 방법
- 서버 Request, Response 객체 설계 (data class)
- Retrofit Interface 구현체 만들기 (ApiService, ServiceCreator)
- callback을 등록하며 통신 요청하기 (Activity, Fragment)
-
recyclerview 데이터바인딩 사용 (repo, follow)
- Item_repository.xml
<?xml version="1.0" encoding="utf-8"?> <layout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"> <data> <variable name="repoData" type="com.example.sopt_1.data.RepositoryInfo" /> </data> ... <TextView android:id="@+id/tv_repository_name" ... android:text="@{repoData.repoName}" .../> <TextView android:id="@+id/tv_repository_info" ... android:text="@{repoData.repoInfo}" ... /> <TextView android:id="@+id/tv_language" ... android:text="@{repoData.repoLanguage}" .../> </androidx.constraintlayout.widget.ConstraintLayout> </layout>
- RepositoryListAdapter.kt
... override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RepositoryViewHolder { val binding = ItemRepositoryBinding.inflate( LayoutInflater.from(parent.context), parent, false ) return RepositoryViewHolder(binding) ... class RepositoryViewHolder( private val binding: ItemRepositoryBinding ) : RecyclerView.ViewHolder(binding.root) { fun onBind(repositoryInfo: RepositoryInfo) { binding.repoData = repositoryInfo } }
- RecyclerView를 사용하여 리스트 만들기
- 팔로잉 화면 구현
- 홈 화면의 User 정보에 more 버튼 추가하여 팔로잉 화면으로 넘어가기 하기
- 홈 화면에 레포지터리 리스트 구현하기 (RecyclerView)
- 레포지터리 이름과 설명이 길 경우 ... 으로 표시
-
Recyclerview에 사용될 item layout 만들기
- item_repository.xml
-
리스트가 보여질 activiry에 Recyclerview 추가
- activity_home.xml에 추가함
-
레포지터리 리스트에 들어갈 내용을 data class 로 만들기
- RepositoryInfo.kt
-
어댑터 클래스 만들기
- RepositoryListAdapter.kt
- RecyclerView.Adapter<RepositoryListAdapter.RepositoryViewHolder>() 상속
- RepositoryListAdapter class 안에 RepositoryViewHolder 클래스도 생성
- Adapter는 ViewHolder로 변경할 Data 가지고 있어야 함
userList = mutableListOf<RepositoryInfo>()
- Adapter는 아이템마다 ViewHolder를 만드는 방법 정의
- Adapter는 전체 아이템의 수 알아야 함
- Adapter는 ViewHolder에 Data 전달하는 방법 정의
-
Recyclerview가 들어갈 화면의 Activity/Fragment에 어댑터 추가
-
HomeActivity.kt
-
// 1. 우리가 사용할 어뎁터의 초기 값을 넣어준다 repositoryListAdapter = RepositoryListAdapter() // 2. RecyclerView 에 어뎁터를 우리가 만든 어뎁터로 만들기 binding.listRepository.adapter = repositoryListAdapter repositoryListAdapter.userList.addAll( listOf<RepositoryInfo>( RepositoryInfo( repoName = "And-Potter/Ravenclaw_HJinhee", repoInfo = "진희의 솝트 레포지터리", repoLanguage = "Kotlin" ), RepositoryInfo( repoName = "레포지터리 이름이 엄청 길 때 ... 표시되도록 하는거 보여주려고 이렇게 길게 쎄보는 중입니다아", repoInfo = "레포지터리 설명이 엄청 길 때 ... 표시되도록 하는거 보여주려고 이렇게 길게 쎄보는 중입니다아", repoLanguage = "Java" ) ) ) repositoryListAdapter.notifyDataSetChanged()
-
- signIn, signUp, home 화면 구현
- activity_sign_in.xml에서 Guidline 활용
- activity_home.xml에서 자기소개 ScrollView 활용
SignInActivity.kt
private val signUpActivityLauncher =
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
//데이터를 받아서 할 일이 들어가는 칸
if (it.resultCode == Activity.RESULT_OK) {
if (intent != null) {
binding.etLoginId.setText(it.data?.extras?.getString("userId"))
binding.etLoginPw.setText(it.data?.extras?.getString("userPw"))
}
}
}
private fun signUpClickEvent() {
binding.tvSignUp.setOnClickListener {
val intent = Intent(this@SignInActivity, SignUpActivity::class.java)
signUpActivityLauncher.launch(intent)
SignUpActivity.kt
private fun signUpButtonClickEvent() {
binding.btnSignUp.setOnClickListener {
...
} else {
//초기 SignUpActivity로 돌아갈 수 있도록 종료
// 종료 전 putExtra를 이용해 모든 값을 intent에 넣어 전달
val intent = Intent(this@SignUpActivity, HomeActivity::class.java)
intent.putExtra("userName", userName.toString())
.putExtra("userId", userId.toString())
.putExtra("userPw", userPw.toString())
setResult(
RESULT_OK,
intent
) //setResult() 메소드로 결과를 저장 -> 성공 : RESULT_OK, 실패 : RESULT_CANCEL
finish()
}
...
-> 이 기능이 사라지면서 registerForActivityResult()에서 처리 가능