3

I am try to learning android jetpack compose, and I have simple app. In ScreenA I have a text field and when I click the button, I am save this data to firestore, and when I come in ScreenB, I want to save city name also in firebase, but I am using one viewmodel, so how can save both text field data in the same place in firestore, I did not find any solution.

ScreenA:

    class ScreenAActivity : ComponentActivity() {



    private lateinit var  viewModel: MyViewModel

    override fun onCreate(savedInstanceState: Bundle?) {

        super.onCreate(savedInstanceState)
     
        viewModel = ViewModelProvider(this)[MyViewModel::class.java]


        setContent {
            ScreenA(viewModel)
        }
     }
   }

  @Composable
  fun ScreenA(

  viewModel : MyViewModel

  ) {

   val name = remember { mutableStateOf(TextFieldValue()) }

      OutlinedTextField(
            value = name.value,   
            onValueChange = { name.value = it },
            label = { Text(text = "name") },
          
        )

        Button(
            modifier = Modifier
                .width(40.dp)
                .height(20.dp),
            onClick = {

                focus.clearFocus(force = true)
                viewModel.onSignUp(
                    name.value.text,
                 
                )
                context.startActivity(
                    Intent(
                        context,
                        ScreenB::class.java
                    )
                )

                },
            colors = ButtonDefaults.buttonColors(
                backgroundColor = Color.Red
            ),
            shape = RoundedCornerShape(60)
        ) {
            Text(
                text = "OK"
             
             )
            )
        }

 }

ScreenB:

class ScreenBActivity : ComponentActivity() {

override fun onCreate(savedInstanceState: Bundle?) {

    super.onCreate(savedInstanceState)

    setContent {
        ScreenB()
    }
 }
}

@Composable
fun ScreenB(

 ) {
val city = remember { mutableStateOf(TextFieldValue()) }

  OutlinedTextField(
        value = city.value,   
        onValueChange = { city.value = it },
        label = { Text(text = "city") },
      
    )

    Button(
        modifier = Modifier
            .width(40.dp)
            .height(20.dp),
        onClick = {

            focus.clearFocus(force = true)
            viewModel.onSignUp(
                city.value.text,
             
            )
           

            },
        colors = ButtonDefaults.buttonColors(
            backgroundColor = Color.Red
        ),
        shape = RoundedCornerShape(60)
    ) {
        Text(
            text = "OK"
         
         )
        )
    }

   }

1 Answers1

5

The recommendation is use a single activity and navigate through screens using Navigation library.

After you've refactored your code to use the Navigation library, you can pass the previous back stack entry in order to get the same instance of the View Model.

val navController = rememberNavController()
NavHost(
    navController = navController,
    ...
) { 
    composable("ScreenA") { backStackEntry ->
        val viewModel: MyViewModel = viewModel(backStackEntry)
        ScreenA(viewModel)
    }
    composable("ScreenB") { backStackEntry ->
        val viewModel: MyViewModel = viewModel(navController.previousBackStackEntry!!)
        ScreenB(viewModel)
    }
} 

But if you really need to do this using activity, my suggestion is define a shared object between the view models. Something like:

object SharedSignInObject {
    fun signUp(name: String) {
        // do something
    }
    // other things you need to share...
}

and in your viewmodels you can use this object...

class MyViewModel: ViewModel() {
    fun signUp(name: String) {
        SharedSignInObject.signUp(name)
    }
}
nglauber
  • 18,674
  • 6
  • 70
  • 75
  • Tnx so much for ur answer, I have to use intent for it now, can you update ur answer for it? I cannot use navcontroller now. –  Apr 18 '22 at 01:08
  • 1
    In according to this answer (from Ian Lake, Googler Developer Advocate), it's not possible... If you really need this, it's better you use a another approach (via Intent extras, Shared Prefs, Database...) https://stackoverflow.com/questions/62845238/how-can-i-share-viewmodel-between-activities – nglauber Apr 18 '22 at 01:14
  • Another suggestion is this answer here: https://stackoverflow.com/questions/57077784/how-to-share-same-instance-of-viewmodel-between-activities-using-koin-di – nglauber Apr 18 '22 at 01:19
  • In Activity1, you use ViewModel1. In Activity2, you use ViewModel2. Both view models are sharing the same instance of `SharedSignInObject`. Therefore, everything you declare/save in `SharedSignInObject` will be available in both activities through the respective View Model. If you do `var x = 10` in `SharedSignInObject`, you can set/get this value from both view models... That's it... Unfortunately I can't be more clear than that... – nglauber Apr 18 '22 at 01:44
  • how we can apply for this one, https://stackoverflow.com/q/71942247/13614484 –  Apr 20 '22 at 19:10