[코드 리팩토링] '미주정복' - 1일차

이윤진·2024년 1월 15일
0

코드 리팩토링

목록 보기
2/12

오늘 할 일

  1. hilt 환경설정
  2. 파일 구조 설계
  3. LoginActivity 파일 코드 리팩토링

LoginActivity 파일 Code 구성

  1. LoginActivity 클래스
  2. Login 화면 구성 compose 함수
  3. 카카오 로그인, 네이버 로그인 함수

바뀐 구성

먼저 mvvm 구조를 따라 view, viewModel로 나누어, UI와 데이터 처리 부분을 구분해주었습니다.

LoginActivity에는 Activity를 구성하는데 필요한 것만 넣어주었습니다.
(sdk 초기화에 필요한 암호들은 --로 처리하여 업로드 합니다.)

@AndroidEntryPoint
class LoginActivity : ComponentActivity() {
    @Inject lateinit var viewModel: LoginViewModel
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            UsDividendTheme {
                // SDK init
                KakaoSdk.init(this, "--")
                NaverIdLoginSDK.initialize(this, "--", "--", "미주정복")

                LoginView(viewModel)
            }
        }
    }
}

LoginView는 @Compose로 화면을 구성하였던 함수만을 넣어주었습니다.
LoginViewModel은 sns 로그인을 실행하고, 서버에 정보를 보내주는 함수를 넣었습니다.
viewModel에서 페이지를 넘기도록 설정하기 위해서 viewModel의 함수에 context를 인자로 넣어주었는데, 찾아보니 이렇게 구현하면 안 되었습니다.
이는 Activity가 onDestroy된 후 ViewModel이 onCleared로 사라지기 때문입니다.

예를 들어 가로 또는 세로로 변경가능한, 화면이 있다고 가정해봅시다.
가로 <-> 세로 모드로 변경할 때는 화면이 onDestroy 이후 onCreate로 다시 이동합니다.
만약 ViewModel에게 context 준다면 화면 방향이 변경된 후의 ViewModel은 이전 화면의 context를 가지고 있게 되는 것입니다.

이를 방지하기 위해서 @ActivityContext를 사용하였다.
ViewModel를 사용하고자 하는 Activity의 context를 사용할 수 있게 해준다.

@HiltViewModel
@AndroidEntryPoint
class LoginViewModel @Inject constructor(
    @ActivityContext private val context: Context
) : ViewModel() {

이렇게 하면
This field leaks a context object 와 같은 warning이 뜨는데 아래의 링크를 확인하면 그냥 업데이트를 하면서 생긴 에러로 warning이 뜨는 것 같다.
https://stackoverflow.com/questions/66216839/inject-context-with-hilt-this-field-leaks-a-context-object

retrofit 설정

mvvm 형태로 또 hilt를 사용하여 구현하기 위해
NetworkModule, LoginRepository 파일을 만들었다.
NetworkModule은 아래의 링크를 참조하여 만들었다.
https://rccode.tistory.com/296

LoginRepository는 apiService의 signUp 함수를 사용할 수 있도록 만들었다.

@AndroidEntryPoint
class LoginRepository @Inject constructor(private val apiService: ApiService) {
    @WorkerThread
    suspend fun signUp(nameEmailData: NameEmailData) = apiService.signUp(nameEmailData)
}

이를 ViewModel에 적용시키면 아래와 같다.

viewModelScope.launch {
    val serverAnswer = loginRepository.signUp(
        NameEmailData(nickname!!, email!!)
    )
    when (serverAnswer.isSuccessful) {
        true -> {
            val data = JSONObject(
                JSONObject(
                    serverAnswer.body().toString()
                ).getString("result")
            )
            val userdata = UserData(
                userId = data.getString("userId").toInt(),
                userName = data.getString("userName"),
                email = data.getString("email"),
                holdingDollar = data.getString("holdingDollar")
                    .toFloat()
            )
            userid = userdata.userId
            holdingDollars = userdata.holdingDollar
            val intent = Intent(
                context,
                MainActivity::class.java
            )
            startActivity(context, intent, null)
        }

        else -> {
            Log.d("Retrofit", "data null")
        }
    }
}

이 코드가 제대로 돌아가는 지 확인해보고 싶은데.. 이 프로젝트를 진행한지 약 10개월이 지나서 서버를 만들 동기가 이 프로젝트를 밀어버렸다고 한다..
그래서 이게 제대로 작동하는 지 알고 싶으면 다른 서버와 통신해봐야 할 것 같다.

전역 변수 사용 바꾸기

코드를 보니 내가 이전에 email, nickname, userid, holdingdollars들을 다른 액티비티들과 같이 사용하기 위해 위의 정보를 전역변수로 바꾸어 쓰고 있었다...

이러면 나중에 비슷한 변수명을 사용할 때 문제가 생길 수 있고 전역변수를 사용하는 것은 좋은 선택이 아니기 때문에 Room을 사용해보기로 했다.

보통은 SharedPreferences를 사용했는데 Room이 Android 권장 사용이기도 하고, 지금 서버가 없어서 구현이 안 되는 부분을 로컬 데이터베이스로 커버해서 개발해보고 싶어졌다.

아마 다음은 Room 설치 및 사용방법에 대한 글이 될 것 같다.

profile
Android/Flutter 개발

0개의 댓글