Sobes.tech
Junior

How to call an activity method from a fragment?

sobes.tech AI

Answer from AI

There are several ways to invoke an activity method from a fragment, depending on the situation and architecture:

  1. Via a reference to the activity:

    The fragment can get a direct reference to the activity it is attached to.

    // Inside the fragment
    if (activity is YourActivity) {
        (activity as YourActivity).yourActivityMethod()
    }
    

    This method is simple but creates a strong dependency between the fragment and a specific activity.

  2. Via a callback interface:

    This is a more flexible and recommended approach. An interface is defined in the fragment, which the activity must implement.

    // Inside the fragment
    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
    }
    
    // Calling the activity method from the fragment
    fun callActivityMethod() {
        listener?.onYourActivityMethodCalled()
    }
    
    // Inside the activity
    class YourActivity : AppCompatActivity(), YourFragment.OnYourActivityMethodListener {
    
        override fun onYourActivityMethodCalled() {
            // Logic to be executed in the activity
        }
    
        // ... rest of the activity code
    }
    

    This approach makes the fragment more reusable, as it depends on a contract (interface) rather than a specific activity class.

  3. Via ViewModel (recommended for more complex interactions):

    Using a shared ViewModel between the fragment and activity allows them to exchange data and events without direct references to each other.

    // Shared ViewModel
    class SharedViewModel : ViewModel() {
        private val _callActivityMethodEvent = MutableLiveData<Event<Unit>>()
        val callActivityMethodEvent: LiveData<Event<Unit>> = _callActivityMethodEvent
    
        fun triggerActivityMethod() {
            _callActivityMethodEvent.value = Event(Unit)
        }
    }
    
    // Wrapper class for LiveData to handle one-time events
    open class Event<out T>(private val content: T) {
        var hasBeenHandled = false
            private set // Allow external read but not write
    
        /**
         * Returns the content and prevents its use again.
         */
        fun getContentIfNotHandled(): T? {
            return if (hasBeenHandled) {
                null
            } else {
                hasBeenHandled = true
                content
            }
        }
    
        /**
         * Returns the content even if it's already been handled.
         */
        fun peekContent(): T = content
    }
    
    // Inside the fragment
    private val sharedViewModel: SharedViewModel by activityViewModels() // Using activityViewModels()
    
    // Calling the activity method via ViewModel
    fun callActivityMethod() {
        sharedViewModel.triggerActivityMethod()
    }
    
    // Inside the activity
    private val sharedViewModel: SharedViewModel by viewModels()
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // ...
    
        sharedViewModel.callActivityMethodEvent.observe(this, Observer { event ->
            event.getContentIfNotHandled()?.let {
                // Logic to be executed in the activity
            }
        })
    }
    

    This approach aligns with architectural component recommendations and facilitates testing.

The choice of method depends on the complexity of the interaction. For simple cases, direct call or interface is suitable. For more complex scenarios, especially involving data transfer, using ViewModel is preferable.

How to call an activity method from a fragment… - sobes.tech