Theoretically, you could have your entire application run on a single Activity and use Fragments for all of the pages.
Each fragment has its own lifecycle within the activity.
MainActivity can look like this
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        loadFragment(2)
    }
    public fun loadFragment(page: Int){
        if(page == 1){
            // load login
            val manager = supportFragmentManager.beginTransaction()
            manager.replace(R.id.fragment_holder, LoginFragment()).commit()
        }else{
            // load register
            val manager = supportFragmentManager.beginTransaction()
            manager.replace(R.id.fragment_holder, LoginFragment()).commit()
        }
    }
}
LoginFragment can look like this
class LoginFragment : Fragment() {
    lateinit var myButton: Button
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
    }
    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        // Inflate the layout for this fragment
        val view = inflater.inflate(R.layout.fragment_login, container, false)
        myButton = view.findViewById(R.id.my_button)
        myButton.apply {
            setOnClickListener { toRegister() }
        }
        return view;
    }
    fun toRegister(){
        // replace the fragment in main activity with register fragment
        (requireActivity() as MainActivity).loadFragment(1)
    }
}
RegisterFragment can look like this
class RegisterFragment : Fragment() {
    lateinit var mButton: Button
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
    }
    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        // Inflate the layout for this fragment
        val view = inflater.inflate(R.layout.fragment_register, container, false)
        mButton = view.findViewById(R.id.my_button)
        mButton.apply {
            setOnClickListener { toLogin() }
        }
        return view;
    }
    fun toLogin(){
        // replacing the fragment in the main activity with the login fragment
        (requireActivity() as MainActivity).loadFragment(1)
    }
}
Basically, we replace the fragment displayed in the activity by calling loadfragment.
This logic can be applied to as many fragments as is necessary.