Implementation Example of and Routing Jump for Data Transfer in Android Modularization

  • 2021-09-16 08:06:20
  • OfStack

Although module communication and routing protocols are not new in Android, if we break away from those excellent open source libraries, we will build our own library from scratch, and sometimes building wheels repeatedly will make us understand the principle of the so-called "car" more thoroughly.

Address of wheels directly built: https://github.com/Neacy/NeacyComponent

This wheel has two major functions: module communication and route jump:

Modular communication

First of all, Unification 1 declares posture:


public interface IComponent {

  String getName();

  void startComponent(ComponentParam param);
}

That is to say, if you want to provide a class for other modules to call in their respective maintenance modules, you need to implement this IComponent class, which can be managed according to the advantages of object-oriented system 1, so we have the following Component classes, such as:


@NeacyComponent("app")
public class AppComponent implements IComponent {

  @Override
  public String getName() {
    return "app";
  }

  @Override
  public void startComponent(ComponentParam param) {
    Log.w("Jayuchou", "==== Start AppComponent ====");
    if (param != null && param.getParam().containsKey("callback")) {
      ICallBack callBack = (ICallBack) param.getParam().get("callback");
      Map<String, Object> results = new HashMap<>();
      results.put("result", " I'm from AppComponent");
      ComponentParam cp = new ComponentParam(results);
      callBack.onComponentBack(cp);
    }
  }
}

Two places are more important:

The NeacyComponent annotation is mainly used for subsequent gradle scans getName () This method returns the key value corresponding to each IComponent, so that we can find the corresponding IComponent object according to this key value in different modules

Secondly, how to call it?


ComponentController.getComponentByName("app").startComponent(null);

Yes, we can easily find the corresponding IComponent object according to the key value of app, and then execute startComponent. This method is where you want to do logic in this module.

Looking at the AppComponent class we declared above, we have judged whether the passed parameters are empty under startComponent. Here, a pseudo Map class is directly put to store the passed parameters.

How to call back the results and how to get the callback results of other modules?

First of all, you executed the startComponent method of other modules. In this method, the class you returned must only be recognized by the corresponding module, that is to say, you can't get the class in other modules in your own module, so here you use ComponentParam to store parameters and callback results in the style of key/value, and then look at the following code to understand the answer.


//  Pass parameters to IComponent ,   You can get the callback result by passing the callback function 
 Map<String, Object> p = new HashMap<>();
 p.put("callback", new ICallBack() {
   @Override
   public void onComponentBack(ComponentParam result) {
     Log.w("Jayuchou", "====  Running result  = " + result.getParam().get("result"));
   }
 });
 ComponentParam cp = new ComponentParam(p);

//  Callback results back 
ICallBack callBack = (ICallBack) param.getParam().get("callback");
Map<String, Object> results = new HashMap<>();
results.put("result", " I'm from AppComponent");
ComponentParam cp = new ComponentParam(results);
callBack.onComponentBack(cp);

//  Pass in parameters when calling 
ComponentController.getComponentByName("app").startComponent(cp);

Routing jump

First of all, the old rule must also be to declare the routing protocol under 1 (here is just a simple string)


@NeacyProtocol("/activity/a")
public class AActivity extends AppCompatActivity

@NeacyProtocol("/activity/b")
public class BActivity extends AppCompatActivity

@NeacyProtocol("/activity/app")
public class MainActivity extends AppCompatActivity

Then call it:


RouterController.startRouter(MainActivity.this, "/activity/a");//  Jump to AActivity

Bundle args = new Bundle(); 
args.putString("key", "AActivity"); 
RouterController.startRouter(AActivity.this, "/activity/b", args);//  Jump to BActivity And carry bundle Parameter 

Principle

The principle is to scan annotations through gradle plug-in combined with ASM and inject code at compile time. Let's first look at the code structure after successful injection:

1. Injection results of module communication


public class ComponentController
{
 static
 {
  registerComponent(new AComponent());
  registerComponent(new BComponent());
  registerComponent(new AppComponent());
 }
 
 private static Map<String, IComponent> components = new HashMap();
 
 static void registerComponent(IComponent component)
 {
  components.put(component.getName(), component);
 }
 . 
 . 
 .
}

2. Routing jump injection results


public class RouterController
{
 static
 {
  addRouter("/activity/a", "com.neacy.neacy_a.AActivity");
  addRouter("/activity/b", "com.neacy.neacy_b.BActivity");
  addRouter("/activity/app", "com.neacy.component.MainActivity");
 }
 
 private static Map<String, String> routers = new HashMap();
 
 public static void addRouter(String key, String value)
 {
  routers.put(key, value);
 }
}

3. For more code on the gradle plug-in, see https://github.com/Neacy/NeacyComponent

Finally

Thanks again for inspiration: https://github.com/luckybilly/CC


Related articles: