Sobes.tech
Junior

Ako zavolať metódu aktivity z fragmentu?

sobes.tech AI

Odpoveď od AI

Existuje niekoľko spôsobov, ako vyvolať metódu aktivity z fragmentu, v závislosti od situácie a architektúry:

  1. Prostredníctvom odkazu na aktivitu:

    Fragment môže získať priamy odkaz na aktivitu, ku ktorej je pripojený.

    // Vo vnútri fragmentu
    if (activity is YourActivity) {
        (activity as YourActivity).yourActivityMethod()
    }
    

    Tento spôsob je jednoduchý, ale vytvára silnú závislosť medzi fragmentom a konkrétnou aktivitou.

  2. Prostredníctvom callback rozhrania:

    Ide o flexibilnejší a odporúčaný spôsob. Definuje sa rozhranie vo fragmente, ktoré musí implementovať aktivita.

    // Vo vnútri fragmentu
    interface OnYourActivityMethodListener {
        fun onYourActivityMethodCalled()
    }
    
    private var listener: OnYourActivityMethodListener? = null
    
    override fun onAttach(context: Context) {
        super.onAttach(context)
        if (context is OnYourActivityMethodListener) {
            listener = context
        } else {
            throw RuntimeException("$context must implement OnYourActivityMethodListener")
        }
    }
    
    override fun onDetach() {
        super.onDetach()
        listener = null
    }
    
    // Volanie metódy aktivity z fragmentu
    fun callActivityMethod() {
        listener?.onYourActivityMethodCalled()
    }
    
    // Vo vnútri aktivity
    class YourActivity : AppCompatActivity(), YourFragment.OnYourActivityMethodListener {
    
        override fun onYourActivityMethodCalled() {
            // Logika, ktorá má byť vykonaná v aktivite
        }
    
        // ... zvyšok kódu aktivity
    }
    

    Tento prístup robí fragment viac opakovane použiteľným, pretože závisí od kontraktu (rozhrania), nie od konkrétnej triedy aktivity.

  3. Prostredníctvom ViewModel (odporúča sa pre zložitejšie interakcie):

    Použitie spoločného ViewModel medzi fragmentom a aktivitou im umožňuje vymieňať si údaje a udalosti bez priameho odkazu na seba.

    // Spoločný ViewModel
    class SharedViewModel : ViewModel() {
        private val _callActivityMethodEvent = MutableLiveData<Event<Unit>>()
        val callActivityMethodEvent: LiveData<Event<Unit>> = _callActivityMethodEvent
    
        fun triggerActivityMethod() {
            _callActivityMethodEvent.value = Event(Unit)
        }
    }
    
    // Obalová trieda pre LiveData na spracovanie udalostí jednorazového prijatia
    open class Event<out T>(private val content: T) {
        var hasBeenHandled = false
            private set // Povolené externé čítanie, ale nie zápis
    
        /**
         * Vráti obsah a zabráni jeho opätovnému použitiu.
         */
        fun getContentIfNotHandled(): T? {
            return if (hasBeenHandled) {
                null
            } else {
                hasBeenHandled = true
                content
            }
        }
    
        /**
         * Vráti obsah aj v prípade, že už bol spracovaný.
         */
        fun peekContent(): T = content
    }
    
    // Vo vnútri fragmentu
    private val sharedViewModel: SharedViewModel by activityViewModels() // Používame activityViewModels()
    
    // Volanie metódy aktivity cez ViewModel
    fun callActivityMethod() {
        sharedViewModel.triggerActivityMethod()
    }
    
    // Vo vnútri aktivity
    private val sharedViewModel: SharedViewModel by viewModels()
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // ...
    
        sharedViewModel.callActivityMethodEvent.observe(this, Observer { event ->
            event.getContentIfNotHandled()?.let {
                // Logika, ktorá má byť vykonaná v aktivite
            }
        })
    }
    

    Tento prístup zodpovedá odporúčaniam architektonických komponentov a uľahčuje testovanie.

Výber metódy závisí od zložitosti interakcie. Pre jednoduché prípady postačí priame volanie alebo rozhranie. Pre zložitejšie scenáre, najmä spojené s prenosom údajov, je vhodnejšie použiť ViewModel.