Home > Software design >  How to pass data from Activity to Fragment KOTLIN?
How to pass data from Activity to Fragment KOTLIN?

Time:12-09

I use a Login Screen with Firebase Auth and Firestore and linked Firestore and Firebase Auth with same e-mail. I am wanting when I login or register to app with e-mail, It have to pass to other Activity's Fragment if it will be successful I can access Firestore. I tried with Bundle and SafeArgs but it always give me null. I can't solve this annoying problem. I will leave my codes.

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)

}

nav_graph.xml

<?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>

CodePudding user response:

The problem here is that You are creating a Fragment instance in the LoginActivity, setting arguments for that Fragment, and then You start a new Activity MainActivity. You are not doing anything with this Fragment reference, it is basically forgotten after You change the Activity.

To better understand that, You should remind yourself of Object Oriented Programming basics logic behind android Fragments Activities.

I suggest to remove the Fragment creation in LoginActivity. Then what You can do to make it work is to:

  1. Firstly add the email to the MainActivity Intent extras.
  2. Now You have the email in your MainActivity and You can pass it to your navGraph startDestination. You can find info on how to do it in other threads, for example: Navigation Architecture Component- Passing argument data to the startDestination
  3. Alternatively you can also use requireActivity() in the Fragment to get to the Activity, but I wouldn't recommend it.

CodePudding user response:

As mentioned by the Mert Ozan, the Fragment reference created in LoginActivity.kt is not referenced in the Main Activity.

Instead of trying to pass the Email address from login activity to main activity. You can access the email of current signed in user directly at the Main Activity.

Something like:

private lateinit var auth: FirebaseAuth
...
override fun onCreate(..)..{ // (or onCreateView depending where u want to access the email)
    ...

    auth = Firebase.getInstance()
    val email = auth.currentUser?.email.toString()

    ...
}
  • Related