LoginInterface는 MVP를 사용할 때 개발자들이 가독성을 위해 즐겨사용하던 명명규칙을 사용해 보세요. (다시 한번 강조하지만, naming이 아주 중요합니다. 가능하면 더 좋은 이름을 짓는 연습을 하세요.) 코딩의 상당시간은 코드 작성이 아니라 코드를 읽는데 보내게 됩니다.
View 에는 View에 필요한 동작을, Presneter에는 Presenter에 맞는 동작을 함수로 포함시키세요. 예를 들면, moveToSignUp은 View 에서 필요한 함수이지, Presenter가 필요한 함수가 아닙니다. 이게 잘 이해가 가지 않으신다면 함수의 몸체 없이 함수이름만 가지고 흐름을 먼저 훓어보시기 바랍니다. 다이어그램을 그려봐도 좋구요.
interface LoginContract {
interface View{
...
fun moveToSignup()
}
interface Presenter{
fun login(emai: Sring, password: String)
}
}
LoginPresenter는 LoginContract.Presenter를 구현하셔야 하고, LoginConract.View를 멤버변수로 기지셔야 합니다.
class LoginPresenter(
var view: LoginContract.View? = null
): LoginContract.View {
private val auth by lazy { FirebaseAuth.getInstance() }
fun login(email: String, password: String) {
if (email.isEmpty() || password.isEmpty()
) {
viewInterface?.MakeToast("아이디와 비밀번호를 모두 입력해주세요")
return
}
// userModel = UserModel(email, password) - 붚필요한 객체. 필요시 Firebsse에서 축축할 수 있음.
requestLogin(email, password)
}
// private 사용
private fun requestLogin(email: String, pasword: Stringl){
auth.signInWithEmailAndPassword(email, password)
.addOnCompleteListener { task ->
if (task.isSuccessful) {
view?.MakeToast("로그인 완료")
view?.moveToSignup()
} else {
view?.MakeToast("아이디 또는 비밀번호가 틀렸습니다")
}
}
}
// 님의 경우 onStart, onStop은 불필요.
}
LoginActivity는 LoginView만 구현하시면 되고 LoginPresenteer는 non-null타입을 사용하시면 됩니다.
class LoginActivity : AppCompatActivity(), View.OnClickListener, LoginContract.View {
...
private lateinit var presenter: LoginContact.Presenter
override fun onCreate(savedInstanceState: Bundle?) {
...
presenter = LoginPresenter()
}
override fun onStart() {
presenter.view = this
...
}
override fun onStop() {
...
presenter.view = null
...
}
...
}
그리고 View 인터페이스와 Presenter인터페이스는 꼭 필요한 동작만 외부에 노출시키면 되고, 함수명을 가능하면 너무 구체적인 것 보다는 좀 더 일반적이 이름을 사용하세요. 예를 들면,
MakeToToast 보다는 showMessage가 더 적합합니다. Presenter는 View가 Toast를 사용할지 Snackbar를 사용하지, Dialog를 사용할지 알 필요가 없습니다. 그리고 이 보다 좀 더 유연한 접근방법은 성공이나 에러메세지를 Presneter에서 구체적으로 지정하지 말고 이벤트형태로 View에 던져주고 거기에 필요한 처리는 View에서 알아서 하도록 하는게 추후에 변경사항같은 것을 적ㅇ요하기에 더 좋습니다. 예를 들면,
enum class LoginUiMessage(@StringRes val resId) {
INVALID_ID_OR_PASSWORD(R.string.invalid_id_or_password),
LOGIN_FAILED(R.string.login_failed)
}
view?.onLoginMessage(LoginUiMessage.INVALID_ID_OR_PASSWORD)
// or
sealed class LoginUiEvent {
object LoginScueess: LoginUiEvent()
object LoginFailure: LoginUiEvent()
}
view?.onLoginEvent(LoginUiEvent.LoginScueess)
그리고 가능하면 메세지 같은 경우는 문자열을 하드코딩하지 마시고 안드로이드 플랫폼의 장점을 활용하기 위해 resource를 이용해서 처리하시는 습관을 들이시기 바랍니다.