두가지 방향이 있습니다. 로그인 관련을 별도의 액티비티로 구성하는 방법(Medium에 보면 은행 앱에 이렇게 구현한 글이 있더라구요)과 로그인이든 뭐든 상관없이 완전히 싱글 액티비티로 가는 경우. 첫번째 방법은 NavHost나 NavController를 하나만 가지고 한군데서 네비게이션 관리가 가능지만, 아래와 같은 문제들을 있고,
- 로그인 여부에 로그인이나 홈 화면을 상황에 맞게 startDestination으로 설정하기
- 로그인 화면에는 툴바나 다른 메뉴가 보이지 않지만 로그인 후에는 보여야 함
두번째 방법은 화면을 깔끔하게 분리할 수 있지만, 로그인은 네비게이션 컴포넌트를 사용함에도 거의 별개의 네비게이션 처럼 된다는 것이죠.
사실 네비게이션 컴포넌트 나오기 전에는 싱글액티비티는 현재 네비게이션 컴포넌트 등에 제공하는 코드를 구현해줘야 했기 때문에 메인액티비티에 불필요한 코드가 엄청 들어가는 God object를 만들게 됨으로써 안티 패턴으로 취급이 되었었는데, 네비게이션을 컨트롤 할 수 있게 되면서 이 부분이 해결되었고 사실 싱글액티비티 사용에는 여러가지 이득이 있습니다. 예를 들면, BaseActivity라는 걸 만들어서 공통코드(예를 들면, 사용자 interaction 체크) 등을 집어넣어서 사용했지만, 싱글액티비티를 사용하면 그럴 필요가 없죠. 이전에 액티비티 레벨에서 무언가를 공통적으로 해주어야 하는 게 있었다면, 엄청 간단해 지게 된거죠. 그리고 기본적으로 프레그먼트가 액티비티 보다는 경량입니다. 메모리 사용도 적고 빠릅니다. 앱 퍼포먼스 향상도 가져올 수 있습니다.
저같은 경우는 첫번째 방법을 사용하는데, 주된 이유는 저는 네비게이션 컴포넌트를 액티비티나 프레그먼트에서 직접 사용하지 않고 제가 만든 클래스에 감싸서 사용하고 있습니다. 그 클래스에서 사용자 로그인 체크 등을 처리합니다.
위에서 언급했던 두가지 문제는 개발자 문서를 보시면 해결방법이 나옵니다.
로그인 상태에 따른 시작화면 설정: 화면시작 시에 로그인 상태를 보고 NavGraph.startDestination을 동적으로 호출해 주면 됨.
화면에 따른 툴바나 메뉴제어: https://developer.android.com/guide/navigation/navigation-ui
전체를 싱글액티비티로 시도해 보시고, 이게 구현이 좀 어렵다면 두번째 방법을 차선책으로 사용해 보시라고 권해드리고 싶네요.
* 로그인 상태에 따라 시작화면을 설정하는 좀 더 자세한 방법은, 네비게이션 그래프에(XML)는 개발자 문서에 나온 것 처럼 홈이 되는 프레그먼를 설정하시면 되고, 메인 액티비티의 onCreate 에서 로그인 상태를 체크하셔서, 로그인이 안된 경우라면 로그인 프레그먼트를 띄운다음 백스택을 클리하고 startDestination을 로그인 프레그먼트로 잡아주시면 됩니다.
아래에 아주 기본적인 코드를 적어 볼게요.
nav_graph.xml
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/nav_graph"
app:startDestination="@id/home_fragment">
<fragment
android:id="@+id/home_fragment"
android:name="HomeFragment"
android:label="Game" />
<fragment
android:id="@+id/login_fragment"
android:name="LoginFragment />
</navigation>
MainActivity
class MainActivity: AppCompatActivity {
override fun onCreate(saveInstance: Bundle?) {
super.onCreate(saveInstance);
setContentView(binding.root);
setupViews();
// 액티비티가 안드로이드 시스템에 의해 다시 생성된 경우(예: 디바이스 로테이션, 다크모드 세팅 등)
// 네비게이션 컴포넌트가 상태를 기억하고 있기 때문에 네비게이션을 초기화하지 않는다.
if (saveInstance != null) {
setupNavigation();
}
}
private fun setupNavigation() {
navController = ...
if (session.isNotLoggedIn) {
goToLogin();
} else {
goHome();
}
}
private fun goToLogin() {
navController.navigate(
R.id.logn_fragment,
null,
navOptions {
popUpTo = R.id.nav_graph,
inclusive = false
}
}
navGraph.startDestination = R.id.login_fragment
}
private fun goHome() {
navController.navigate(
R.id.home_fragment,
null,
navOptions {
popUpTo = R.id.nav_graph,
inclusive = false
}
}
navGraph.startDestination = R.id.home_fragment
}
}