Butterfly, Butterfly
Making the address
Butterfly – small and powerful weapon, have it, make your Android development more powerful, Carry all!
Only the strongest and most experienced warriors can wield the butterfly, but it provides incredible dexterity in battle
Item description: +30 Agility +35% dodge +25 attack +30 attack speed
Function is introduced
Butterfly uses two different annotations to achieve different functions:
- Agile is used for page navigation
- It is used for componentized communication
Agile
- navigation
By adding Agile annotations to the Activity and setting the corresponding scheme, you can then navigate through Butterfly or navigate and retrieve returned data
@Agile("test/scheme")
class AgileTestActivity : AppCompatActivity() {
/ /...
}
/ / navigation
Butterfly.agile("test/scheme").carry()
// Navigate and get the returned data
Butterfly.agile("test/scheme")
.carry {
val result = it.getStringExtra("result")
binding.tvResult.text = result
}
Copy the code
- Passing parameters
Agile supports parameter navigation. There are two ways to add parameters to Scheme by concatenating scheme, pass parameters manually by calling the Params method, or mix the two methods, and then obtain the corresponding parameters on the navigated page
/ / stitching scheme
Butterfly.agile("test/scheme? a=1&b=2").carry()
/ / call params
Butterfly.agile("test/scheme? a=1&b=2")
.params("intValue" to 1)
.params("booleanValue" to true)
.params("stringValue" to "test value")
.carry()
Copy the code
- Analytical parameters
On the navigation destination page, you can obtain the value of the passed parameter by using the key field of the parameter
@Agile("test/scheme")
class AgileTestActivity : AppCompatActivity() {
val a bylazy { intent? .getStringExtra("a") ?: "" }
val b bylazy { intent? .getStringExtra("b") ?: "" }
val intValue bylazy { intent? .getIntExtra("intValue".0) ?: 0}}Copy the code
In addition to manual parameter parsing, Bracer can also be equipped to fully automatic parameter parsing
@Agile("test/scheme")
class AgileTestActivity : AppCompatActivity() {
val a by params<String>()
val b by params<String>()
val intValue by params<Int>()
}
Copy the code
See Github address Bracer for more details on how to use Bracer
- The interceptor
Agile supports interceptors, which can be used to pre-process some logic before navigation, such as login detection. Navigation can also be performed in interceptors, but to avoid interceptor traps, you need to add the skipInterceptor() method to ignore interceptors
// Implement custom interceptors
class TestInterceptor : ButterflyInterceptor {
override fun shouldIntercept(agileRequest: AgileRequest): Boolean {
// Check whether interception is required
return true
}
override suspend fun intercept(agileRequest: AgileRequest) {
// Handle the interception logic
println("intercepting")
delay(5000)
println("intercept finish")}}// Register interceptors
ButterflyCore.addInterceptor(TestInterceptor())
// Skip the interceptor
Butterfly.agile("test/scheme").skipInterceptor().carry()
Copy the code
- Action
In addition to supporting page navigation, Agile also supports navigation actions. Actions have no page, so you can do some logic processing: first, let the custom Class inherit the Action, then add @Agile annotation and set scheme, and the rest is consistent with the page navigation
@Agile("test/action")
class TestAction : Action {
override fun doAction(context: Context, scheme: String.data: Bundle) {
// Get the parameters passed in from data
Toast.makeText(context, "This is an Action", Toast.LENGTH_SHORT).show()
}
}
/ / start the Action
Butterfly.agile("test/action").carry()
//Action also supports parameter passing
Butterfly.agile("test/action? a=1&b=2").carry()
/ / params refs
Butterfly.agile("test/action")
.params("intValue" to 1)
.carry()
Copy the code
- Process control
Agile can not only call carry navigation directly, but also call Flow to return the flow object, which can be used to process the navigation process
Butterfly.agile("test/scheme").flow()
.onStart { println("start") }
.onCompletion { println("complete") }
.onEach { println("process result") }
.launchIn(lifecycleScope)
Copy the code
Evade
Butterfly uses two simple annotations to communicate between arbitrary components without any direct or indirect dependencies between components
For example, there are two components: Module Foo and Module Bar that need to communicate
In Module Foo, define the interface, and add the note Evade:
@Evade
interface Home {
// Define the method
fun showHome(fragmentManager: FragmentManager, container: Int)
}
Copy the code
In the Module Bar, define the implementation, and add the EvadeImpl annotation:
// The implementation class name must end with Impl
@EvadeImpl
class HomeImpl {
val TAG = "home_tag"
// Implement a method in the Home interface with the same name and parameters
fun showHome(fragmentManager: FragmentManager, container: Int) {
val homeFragment = HomeFragment()
fragmentManager.beginTransaction()
.replace(container, homeFragment, TAG)
.commit()
}
}
Copy the code
Since the class name is used as an important basis for defining and implementing the association, the interface class name and implementation class name must be the same, and the implementation class name ends with Impl.
If the class name cannot be used as the association, the same string type can be used as the association key
@Evade(identity = "same key")
interface Home
@EvadeImpl(identity = "same key")
class OtherNameImpl
Copy the code
In Module Foo, you can then use the evade method to retrieve the Home and call:
val home = Butterfly.evade<Home>()
home.showHome(supportFragmentManager, R.id.container)
Copy the code
In addition, it also supports strongly associative communication in the form of submergence dependency
For example, the following three components: common components Module Base, Module Foo, and Module Bar
First drop the Home interface into the common component Module Base:
@Evade
interface Home {
fun showHome(fragmentManager: FragmentManager, container: Int)
}
Copy the code
Then, in the Module Bar, implement the interface:
// The same naming rules are used, and the implementation class name must end with Impl
@EvadeImpl
class HomeImpl : Home {
val TAG = "home_tag"
override fun showHome(fragmentManager: FragmentManager, container: Int) {
val homeFragment = HomeFragment()
fragmentManager.beginTransaction()
.replace(container, homeFragment, TAG)
.commit()
}
}
Copy the code
Later, in Module Foo, you can use the evade method to retrieve the Home and call:
val home = Butterfly.evade<Home>()
home.showHome(supportFragmentManager, R.id.container)
Copy the code
The routing table
Butterfly generates a routing table for each annotated Module, named Butterfly[Module name]Module
Manual registration:
class DemoApplication : Application() {
override fun onCreate(a) {
super.onCreate()
/ / register
ButterflyCore.addModule(ButterflyHomeModule())
ButterflyCore.addModule(ButterflyFooModule())
ButterflyCore.addModule(ButterflyBarModule())
}
}
Copy the code
Automatic registration using plug-ins:
- Adding plug-in dependencies
// Use plugins:
plugins {
id "io.github.ssseasonnn.butterfly" version "1.0.1"
}
// Use legacy Plugin application:
buildscript {
repositories {
maven {
url "https://plugins.gradle.org/m2/"
}
}
dependencies {
classpath "IO. Making. Ssseasonnn: plugin: 1.0.1." "}}/ / add the plugin
apply plugin: "io.github.ssseasonnn.butterfly"
Copy the code
- Implement your own Application class
class DemoApplication : Application() {
override fun onCreate(a) {
super.onCreate()
}
}
Copy the code
Confuse configuration
-keep public class zlc.season.butterfly.module.** -keep public class zlc.season.butterfly.annotation.** -keep public class zlc.season.butterfly.ButterflyCore {*; } -keep public class * extends zlc.season.butterfly.Action -keep @zlc.season.butterfly.annotation.Agile class * {*; } -keep @zlc.season.butterfly.annotation.Evade class * {*; } -keep @zlc.season.butterfly.annotation.EvadeImpl class * {*; }Copy the code
As the saying goes, butterfly in hand, the world I have! Don’t you want a piece of this?
Making the address