Skip to content

ComponentCommunicate

Season edited this page Dec 8, 2023 · 1 revision

Basic Usage

Butterfly implements component-based communication through Evade and EvadeImpl annotations. And the communication between components without any dependence is supported by dynamic agent technology.

1. Communicate between components that have no dependencies

For example, two components, Home and Dashboard, component Dashboard need to call the method in the component Home:

flowchart TD
	A(Main App) --> B(Component Home)
	A(Main App) --> C(Component Dashboard)
Loading
//Define the Api that needs to access the Home in the component Dashboard and add the @ Evade annotation
@Evade
interface DashboardCallHomeApi {
    fun showHome(fragmentManager: FragmentManager, container: Int)
}


//Implement the corresponding Api in the component Home and add the @ EvadeImpl annotation
@EvadeImpl
class DashboardCallHomeApiImpl {  //The implementation class name must end with Impl
    val TAG = "home_tag"

    //For the implementation of HomeApi, the method name and parameters must be the same
    fun showHome(fragmentManager: FragmentManager, container: Int) {
        val homeFragment = HomeFragment()
        fragmentManager.beginTransaction()
            .replace(container, homeFragment, TAG)
            .commit()
    }
}

//You can then invoke the interface in the component Home in the component Dashboard:
val dashboardCallHomeApi = Butterfly.evade<DashboardCallHomeApi>()
dashboardCallHomeApi.showHome(supportFragmentManager, R.id.container)

This solution uses dynamic proxy technology to achieve cross component invocation, so it is necessary to ensure that the method names and parameters of the interface and implementation class are consistent, In some simple scenarios, communication between components can be quickly achieved, but due to the inability to ensure the correctness of interface definition and implementation during compilation, Therefore, it is only recommended to use in some special scenarios.

2. Communicate when there is a common underlying dependency between components

It is also two components: Home and component Dashboard. The component Dashboard needs to call the method in the component Home But the difference is that both components rely on the underlying Common component.

flowchart TD
	A(Main App) --> B(Component Home)
	A(Main App) --> C(Component Dashboard)
    B(Component Home) --> D(Component Common)
    C(Component Dashboard) --> D(Component Common)
Loading

Because of the participation of public components, we can put the definition of Api in the Common component.

//Define the Api that needs to access the Home in the component Common and add the @Evade annotation
@Evade
interface HomeApi {
    fun showHome(fragmentManager: FragmentManager, container: Int)
}


//Implement the Api interface in the component Home and add the @EvadeImpl annotation
@EvadeImpl
class HomeApiImpl : HomeApi{  //Implementation class names must also end with Impl
    val TAG = "home_tag"
    
    override fun showHome(fragmentManager: FragmentManager, container: Int) {
        val homeFragment = HomeFragment()
        fragmentManager.beginTransaction()
            .replace(container, homeFragment, TAG)
            .commit()
    }
}

//You can then invoke the interface in the component Home in the component Dashboard:
val homeApi = Butterfly.evade<HomeApi>()
homeApi.showHome(supportFragmentManager, R.id.container)

The participation of common components ensures that the interfaces are correct during compilation, but the downside is that as the project grows, the Common components become bloated.

Recommended

The above two schemes can achieve component-based communication, but only limited to small projects, with the expansion of the project scale, these two schemes are not the optimal solution.

The recommended component-based communication scheme is to Api components, that is, each component is composed of the component itself and its exposed Api components. Components that need to communicate only rely on Api components, which can ensure the correctness of interfaces during compilation and reduce the burden of Common components.

flowchart TD
    A(Main App) --> B(Component Home)
    A(Main App) --> C(Component Dashboard)
    B1(Component Home Api)
    C1(Component Dashboard Api)
    
    B & C --> B1 & C1
Loading