Je souhaite savoir quand le bouton clique sur le fragment et mettre à jour MainActivity. Ce code fonctionne bien, mais lorsque l'écran est tourné en raison de l'activité LifeCycle OnCreate appelé à nouveau et viewModel.nav.observe appelé à nouveau avec la nouvelle valeur true , mais je souhaite qu'il ne soit appelé que sur le bouton. Ce dont j'ai besoin est onClick, la valeur sera définie sur true , puis false , donc je ne sais que lorsque le bouton clique et non sur la rotation de l'écran. Ou une autre façon de savoir que le bouton est cliqué dans le fragment.
Comment puis-je atteindre cet objectif?
Fragment
class SharedViewModel : ViewModel() { var nav = MutableLiveData(false) }
Activité principale
class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) val viewModel = ViewModelProvider(this).get(SharedViewModel::class.java) var fragment1 = Fragment1.newInstance() navigateToFragment(fragment1) viewModel.nav.observe(this, { Log.d("DTAG", "Status: $it") }) } private fun navigateToFragment(fragment: Fragment) { val fragmentTransaction = supportFragmentManager.beginTransaction() fragmentTransaction.addToBackStack(null) fragmentTransaction.replace(R.id.mainFrame, fragment) fragmentTransaction.commit() } }
VoirModèle
class Fragment1 : Fragment() { companion object { fun newInstance() = Fragment1() } private lateinit var viewModel: SharedViewModel override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { return inflater.inflate(R.layout.fragment_1, container, false) } override fun onActivityCreated(savedInstanceState: Bundle?) { super.onActivityCreated(savedInstanceState) viewModel = ViewModelProvider(requireActivity()).get(SharedViewModel::class.java) buttonNextF1.setOnClickListener { viewModel.nav.value = true } } }
3 Réponses :
Il s'agit d'un comportement par défaut des objets LiveData
qui garantissent la mise à jour de leurs valeurs même en cas de modifications de configuration.
Mais pour que cela fonctionne uniquement sur un clic de bouton, et non sur un changement de configuration, vous pouvez accepter ce comportement, mais obtenir un hack dans le rappel d' observe
en utilisant un champ booléen indiquant s'il s'agit d'un nouveau lancement / rotation d'écran, et être renvoyé de l' observe()
quand c'est une rotation.
class MainActivity : AppCompatActivity() { var isRotated: Boolean = true override fun onCreate(savedInstanceState: Bundle?) { // ................. your code viewModel.nav.observe(this, { if (isRotated) { isRotated = false return@observe } Log.d("DTAG", "Status: $it") }) // ................. rest of your code
Vous pouvez utiliser SingleLiveEvent pour atteindre votre objectif car:
Étape 1: Créez un fichier SingleLiveEvent.kt
viewModel.nav.observe(this, Observer { Log.d("DTAG", "Status: $it") })
Étape 2: dans SharedViewModel
class SharedViewModel : ViewModel() { var nav = SingleLiveEvent<Boolean>() }
Étape 3: dans MainActivity
class SingleLiveEvent<T> : MutableLiveData<T?>() { private val mPending = AtomicBoolean(false) @MainThread override fun observe(owner: LifecycleOwner, observer: Observer<in T?>) { if (hasActiveObservers()) { Log.w( TAG, "Multiple observers registered but only one will be notified of changes." ) } // Observe the internal MutableLiveData super.observe(owner, Observer { t -> if (mPending.compareAndSet(true, false)) { observer.onChanged(t) } }) } @MainThread override fun setValue(t: T?) { mPending.set(true) super.setValue(t) } /** * Used for cases where T is Void, to make calls cleaner. */ @MainThread fun call() { value = null } companion object { private const val TAG = "SingleLiveEvent" } }