-
Notifications
You must be signed in to change notification settings - Fork 16
ComponentCommunicate
Butterfly implements component-based communication through Evade
and EvadeImpl
annotations. And the communication between components without any dependence
is supported by dynamic agent technology.
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)
//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.
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)
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.
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