1
votes

Bouton d'activation de Live Data Observer Cliquez lors de la rotation de l'écran

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


0 commentaires

3 Réponses :


0
votes

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 


0 commentaires

1
votes

Vous pouvez utiliser SingleLiveEvent pour atteindre votre objectif car:

  • Vous ne souhaitez notifier l'événement (cliquez sur le bouton sur le fragment) qu'une seule fois
  • Il n'y a qu'un seul observateur (MainActivity) qui observe sur LiveData

É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"
    }
}


0 commentaires

0
votes

Utilisez simplement saveStateViewMode, documentez ici


0 commentaires