Sobes.tech
Junior

Como chamar o método de atividade a partir de um fragmento?

sobes.tech IA

Resposta da IA

Existem várias formas de chamar o método de uma atividade a partir de um fragmento, dependendo da situação e da arquitetura:

  1. Através de uma referência à atividade:

    O fragmento pode obter uma referência direta à atividade à qual está ligado.

    // Dentro do fragmento
    if (activity is YourActivity) {
        (activity as YourActivity).yourActivityMethod()
    }
    

    Este método é simples, mas cria uma dependência forte entre o fragmento e uma atividade específica.

  2. Através de uma interface de callback:

    É um método mais flexível e recomendado. Uma interface é definida no fragmento, que a atividade deve implementar.

    // Dentro do fragmento
    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 deve implementar OnYourActivityMethodListener")
        }
    }
    
    override fun onDetach() {
        super.onDetach()
        listener = null
    }
    
    // Chamada do método da atividade a partir do fragmento
    fun callActivityMethod() {
        listener?.onYourActivityMethodCalled()
    }
    
    // Dentro da atividade
    class YourActivity : AppCompatActivity(), YourFragment.OnYourActivityMethodListener {
    
        override fun onYourActivityMethodCalled() {
            // Lógica que deve ser executada na atividade
        }
    
        // ... resto do código da atividade
    }
    

    Esta abordagem torna o fragmento mais reutilizável, pois depende do contrato (interface), e não de uma classe de atividade específica.

  3. Através de ViewModel (recomendado para interações mais complexas):

    O uso de um ViewModel compartilhado entre o fragmento e a atividade permite trocar dados e eventos, sem referências diretas.

    // ViewModel compartilhado
    class SharedViewModel : ViewModel() {
        private val _callActivityMethodEvent = MutableLiveData<Event<Unit>>()
        val callActivityMethodEvent: LiveData<Event<Unit>> = _callActivityMethodEvent
    
        fun triggerActivityMethod() {
            _callActivityMethodEvent.value = Event(Unit)
        }
    }
    
    // Classe de envolvimento para LiveData para lidar com eventos de uma única vez
    open class Event<out T>(private val content: T) {
        var hasBeenHandled = false
            private set // Permite leitura externa, mas não escrita
    
        /**
         * Retorna o conteúdo e impede seu uso novamente.
         */
        fun getContentIfNotHandled(): T? {
            return if (hasBeenHandled) {
                null
            } else {
                hasBeenHandled = true
                content
            }
        }
    
        /**
         * Retorna o conteúdo mesmo que já tenha sido tratado.
         */
        fun peekContent(): T = content
    }
    
    // Dentro do fragmento
    private val sharedViewModel: SharedViewModel by activityViewModels() // Usando activityViewModels()
    
    // Chamada do método da atividade via ViewModel
    fun callActivityMethod() {
        sharedViewModel.triggerActivityMethod()
    }
    
    // Dentro da atividade
    private val sharedViewModel: SharedViewModel by viewModels()
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // ...
    
        sharedViewModel.callActivityMethodEvent.observe(this, Observer { event ->
            event.getContentIfNotHandled()?.let {
                // Lógica que deve ser executada na atividade
            }
        })
    }
    

    Esta abordagem está de acordo com as recomendações dos componentes arquiteturais e facilita os testes.

A escolha do método depende da complexidade da interação. Para casos simples, uma chamada direta ou uma interface são suficientes. Para cenários mais complexos, especialmente relacionados com a transferência de dados, é preferível usar ViewModel.