You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Kotlin:登录后Activity向Fragment传值返回Null问题求助

问题:Firebase登录后邮箱无法通过Bundle/SafeArgs传递到Fragment

我用Firebase Auth和Firestore实现登录界面,两者通过同一邮箱关联。希望在邮箱登录或注册成功后,将邮箱传递到MainActivity的MainFragment中,用于访问Firestore。尝试用Bundle和SafeArgs传值,但始终返回Null,相关代码如下:

LoginActivity.kt

private val db = Firebase.firestore.collection("users")
private val auth = Firebase.auth
private lateinit var binding: ActivityLoginBinding

private fun loginUser(email: String, password: String) {
        if (email.isNotEmpty() && password.isNotEmpty()) {
            CoroutineScope(Dispatchers.IO).launch {
                try {
                    auth.signInWithEmailAndPassword(email, password)
                        .addOnSuccessListener {
                            val fragment = MainFragment()
                            val bundle = Bundle()
                            bundle.putString("mail", email)
                            fragment.arguments = bundle
                            checkLogged()
                            Toast.makeText(this@LoginActivity, "Welcome Again", Toast.LENGTH_SHORT)
                                .show()
                        }
                        .addOnFailureListener {
                            Toast.makeText(this@LoginActivity, it.message, Toast.LENGTH_LONG).show()
                        }.await()
                } catch (e: Exception) {
                    withContext(Dispatchers.Main) {
                        Toast.makeText(this@LoginActivity, e.message, Toast.LENGTH_LONG).show()
                    }
                }
            }
        }
    }

    private fun registerUser(email: String, password: String, user: User) {
        if (email.isNotEmpty() && password.isNotEmpty()) {
            CoroutineScope(Dispatchers.IO).launch {
                try {
                    auth.createUserWithEmailAndPassword(email, password)
                        .addOnSuccessListener {
                            db.document(user.email).set(user)
                            val fragment = MainFragment()
                            val bundle = Bundle()
                            bundle.putString("email", user.email)
                            fragment.arguments = bundle
                            checkLogged()
                            Toast.makeText(
                                this@LoginActivity,
                                "Welcome ${user.name}",
                                Toast.LENGTH_SHORT
                            ).show()
                        }.await()
                } catch (e: java.lang.Exception) {
                    withContext(Dispatchers.Main) {
                        Toast.makeText(this@LoginActivity, e.message, Toast.LENGTH_LONG).show()
                    }
                }
            }
        }
    }

    private fun checkLogged() {
        if (Firebase.auth.currentUser != null) {
            Firebase.auth.currentUser!!.reload()
            startActivity(Intent(this@LoginActivity, MainActivity::class.java))
            finish()
        } else {
            //
        }
    }

MainFragment.kt

class MainFragment : Fragment() {

private val db = Firebase.firestore.collection("users")
private lateinit var binding: FragmentMainBinding

override fun onCreateView(
    inflater: LayoutInflater, container: ViewGroup?,
    savedInstanceState: Bundle?
): View {
    binding = FragmentMainBinding.inflate(inflater, container, false)
    if (arguments != null){
        val textName = arguments?.getString("email")
        binding.txtName.text = textName
    }
    return binding.root
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)

}
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/nav_graph"
    app:startDestination="@id/mainFragment">
    <fragment
        android:id="@+id/addMealFragment"
        android:name="com.meetozan.caloriecounter.AddMealFragment"
        android:label="fragment_add_meal"
        tools:layout="@layout/fragment_add_meal" />
    <fragment
        android:id="@+id/calendarFragment"
        android:name="com.meetozan.caloriecounter.CalendarFragment"
        android:label="fragment_calendar"
        tools:layout="@layout/fragment_calendar" />
    <fragment
        android:id="@+id/foodsFragment"
        android:name="com.meetozan.caloriecounter.FoodsFragment"
        android:label="fragment_foods"
        tools:layout="@layout/fragment_foods" />
    <fragment
        android:id="@+id/leaderboardFragment"
        android:name="com.meetozan.caloriecounter.LeaderboardFragment"
        android:label="fragment_leaderboard"
        tools:layout="@layout/fragment_leaderboard" />
    <fragment
        android:id="@+id/mainFragment"
        android:name="com.meetozan.caloriecounter.MainFragment"
        android:label="fragment_main"
        tools:layout="@layout/fragment_main">
        <action
            android:id="@+id/action_mainFragment_to_addMealFragment"
            app:destination="@id/addMealFragment" />
        <action
            android:id="@+id/action_mainFragment_to_calendarFragment"
            app:destination="@id/calendarFragment" />
        <action
            android:id="@+id/action_mainFragment_to_foodsFragment"
            app:destination="@id/foodsFragment" />
        <action
            android:id="@+id/action_mainFragment_to_leaderboardFragment"
            app:destination="@id/leaderboardFragment" />
        <argument
            android:name="email"
            app:argType="string"
            app:nullable="true" />
    </fragment>
    <activity
        android:id="@+id/loginActivity"
        android:name="com.meetozan.caloriecounter.LoginActivity"
        android:label="activity_login"
        tools:layout="@layout/activity_login" />
</navigation>

解决方案

问题根源

你在LoginActivity里手动创建了MainFragment实例并设置Bundle,但最终启动的是MainActivity——MainActivity中的MainFragment是由导航组件自动初始化的,和你手动创建的实例完全无关,所以参数根本传不到目标Fragment里。

方案1:通过Intent传递邮箱到MainActivity,再在Fragment中获取

  1. 修改LoginActivity的checkLogged方法,接收邮箱参数并通过Intent传递:
private fun checkLogged(email: String) {
    if (Firebase.auth.currentUser != null) {
        Firebase.auth.currentUser!!.reload()
        val intent = Intent(this@LoginActivity, MainActivity::class.java)
        intent.putExtra("user_email", email)
        startActivity(intent)
        finish()
    }
}
  1. 在loginUser和registerUser的addOnSuccessListener中,调用checkLogged时传入对应邮箱:
    • loginUser里:checkLogged(email)
    • registerUser里:checkLogged(user.email)
  2. 在MainFragment中从Activity的Intent获取参数:
override fun onCreateView(
    inflater: LayoutInflater, container: ViewGroup?,
    savedInstanceState: Bundle?
): View {
    binding = FragmentMainBinding.inflate(inflater, container, false)
    // 从Activity的Intent中读取邮箱
    val email = activity?.intent?.getStringExtra("user_email")
    email?.let {
        binding.txtName.text = it
        // 用该邮箱访问Firestore
        db.document(it).get().addOnSuccessListener { doc ->
            // 处理用户数据
        }
    }
    return binding.root
}

方案2:用导航组件SafeArgs直接跳转(符合Jetpack规范)

  1. 确保项目已启用SafeArgs(在app模块的build.gradle中配置),然后在nav_graph.xml中添加LoginActivity到MainFragment的action:
<activity
    android:id="@+id/loginActivity"
    android:name="com.meetozan.caloriecounter.LoginActivity"
    android:label="activity_login"
    tools:layout="@layout/activity_login">
    <action
        android:id="@+id/action_loginActivity_to_mainFragment"
        app:destination="@id/mainFragment"/>
</activity>
  1. 修改LoginActivity的跳转逻辑,替换checkLogged方法,直接用导航组件跳转并传参:
// 在loginUser的addOnSuccessListener中
val action = LoginActivityDirections.actionLoginActivityToMainFragment(email)
findNavController().navigate(action)
finish()

// 在registerUser的addOnSuccessListener中
val action = LoginActivityDirections.actionLoginActivityToMainFragment(user.email)
findNavController().navigate(action)
finish()
  1. 在MainFragment中用SafeArgs获取参数:
override fun onCreateView(
    inflater: LayoutInflater, container: ViewGroup?,
    savedInstanceState: Bundle?
): View {
    binding = FragmentMainBinding.inflate(inflater, container, false)
    val args = MainFragmentArgs.fromBundle(requireArguments())
    args.email?.let {
        binding.txtName.text = it
    }
    return binding.root
}

方案3:直接从Firebase Auth获取邮箱(最可靠,无需传值)

既然已经集成了Firebase Auth,登录成功后可以直接在MainFragment中获取当前用户的邮箱,完全不需要手动传值:

override fun onCreateView(
    inflater: LayoutInflater, container: ViewGroup?,
    savedInstanceState: Bundle?
): View {
    binding = FragmentMainBinding.inflate(inflater, container, false)
    val currentUser = Firebase.auth.currentUser
    currentUser?.email?.let { userEmail ->
        binding.txtName.text = userEmail
        // 用该邮箱访问Firestore
        db.document(userEmail).get().addOnSuccessListener { document ->
            if (document.exists()) {
                val user = document.toObject(User::class.java)
                // 处理用户数据
            }
        }
    }
    return binding.root
}

这个方法避免了传值过程中可能出现的错误,是最推荐的实现方式。


内容的提问来源于stack exchange,提问作者Mert Ozan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 10:05:36