[Top] ARouter source code analysis of routing scheme

content

  • foreword
  • Jump using Intent
  • Use scheme to complete the jump
  • Officially start the exploration of ARouter
  • summary

foreword

At the end of last year, I shared an analysis of the source code of ARouter when I shared the technology inside the company. Recently, I was sorting out the content in the draft box, and by the way, I shared it and recorded it.

Jump using Intent

In our usual development process, there will be jumps of various pages. For example, when LoginActivity jumps to
HomeActivity, our most common usage may be as follows:

Intent intent = new Intent(context,HomeActivity.class);
intent.putExtra(key,xxx)
startActivity(intent);

This method is no problem in the single-project and single-component development mode, but if the scale of the project gradually increases and the direction of component development gradually evolves, there will be many pits in this method. The most obvious point is that each component There will be strong dependencies on other modules.
In order to avoid this embarrassing problem, we are bound to seek a way to decouple the dependencies between components, or to reduce the dependencies between components as much as possible. You can use an implicit call:

Using the implicit calling method of the system and configuring the corresponding action in the corresponding manifest configuration file, you can complete page jumping and data transfer across components

But have you ever thought about a problem, as the project grows, there are more and more pages, and the corresponding configuration will gradually increase, which will undoubtedly increase the maintenance cost of the project. It can only be said that this is a solution, but Not the best solution.

Use scheme to complete the jump

Based on the enhancement scheme of the previous scheme, a large number of configurations are configured in the list, which is not easy to maintain and feels troublesome. That's fine. We can use a unified proxy ProxyActivity, set the size to 1 pixel, the theme is transparent, and all data is Complete the jump to the specified page through the scheme.

This method solves the previous need to register a large number of list configurations. All jumps are entered through this class. After the processing is completed, the page is closed without knowing it. However,
there is a new problem. The modules of each jump are coupled together, in other words, it is not universal enough. If the jump parameters change, we need to go here to re-change the jump parameters. If there are many jump pages in the app, there will be a lot of changes here. , so the nested dependency problem of multi-project and multi-component has not been fundamentally solved.

思考: How to design a general jump component that has nothing to do with business?

Officially start the exploration of ARouter

A lot has been said above, and here is the real topic. In order to seek a more general and business-independent way to deal with this problem, I also Googled some wheels and found Alibaba's open source wheel ARouter (this last issue shared component-based development The classmates have already mentioned it), let's explore how this wheel is implemented in Ali's source code, but I personally don't want to introduce too much source code content, the first is that it is easy to make people drowsy, The second is that I prefer to express it intuitively in the form of drawings.

Three core modules of ARouter:

//Compiler processor
arouter-compiler
//Core Api
arouter-api
//Annotation
arouter-annotation

The first module arouter-annotation

The content of this module is not much. It is mainly used to store some annotation and enumeration type files. You can have a general impression in your heart. You can come back here to see the function of each file according to the diagram.

file name describe
Route.java Routing annotation, used to mark routing path, grouping, priority and other information
Autowired.java Autowiring annotations for injecting parameters
Interceptor.java Intercept annotation, used to mark information such as interception priority
RouteMeta.java The most basic data information of routing, including routing type, target class, routing path, routing group, priority, extra information, parameter type, etc.
RouteType.java Routing type, there are Activity, Service, ContentProvider, Fragment, etc.

The second module arouter-compiler

The main function of this module is to filter several annotations (Route, Autowired, Interceptor) defined in the first module during compilation, and then generate intermediate code during compilation

file name describe
RouteProcessor.java route processor
InterceptorProcessor.java Intercept handler
AutowiredProcessor.java Assembly processor
TypeUtils.java Type exchange tool class

Let's start at compile time and look at them one by one:

RouteProcessor

Mainly obtain Route-annotated classes between compilers and generate routing tables. The main methods are as follows:

//Parse routing elements
private void parseRoutes(Set routeElements);
//Classify routing metadata
private void categories(RouteMeta routeMete);
//Verify the path and grouping information in routing metadata
private boolean routeVerify(RouteMeta meta);

A simple diagram is summarized as follows:

According to the information in the figure (it is recommended to debug the source code of ARouter in the reader area, in fact, the amount of code is not large), we can see that during compilation, the process method in RouteProcessor will obtain the set of elements filtered in the environment variable, which will be parsed by the parseRoutes method. And
generate intermediate classes generated during compilation, the naming rules are工程名+$$+Group+$$+模块名

1. Construct different types of RouteMeta according to different RouteTypes
2. Group the generated RouteMetes and store them in the groupMap
3. Traverse the groupMap and use the JavaPoet syntax to write the intermediate class files into the build directory

InterceptorProcessor

Its function is mainly to generate the relevant code of the interceptor during compiler compilation (because the page we jump to may require login) The
main method

//parse interceptor
private void parseInterceptors(Set elements);
//brief interceptor element
private boolean verify(Element element);

AutowiredProcessor

// Traverse the classes marked with Autowired
private void generateHelper();
// Build some declarations
private String buildStatement(String statment, int type, boolean isActivity);
// Classify autowired fields
private void categories(Set

The third module arouter-api

Before I talk about the third module, I don't want to directly attack the source code. I think another way. I believe that before we understand a useful wheel, we usually start with use. Then we start with use and explore with questions. :

1.ARouter.init();
2.ARouter.getInstance().build(“/fungo/home”).navigation();
I won’t talk about the introduction of relevant dependencies and markup annotations, but it’s just these two steps. You can complete a basic routing jump, simple and rude.
Start with the first step: what exactly does initialization do? Can it be called directly without initialization? No nonsense, go directly to the source code


It can be seen that the real implementation is not itself, but _ARouter, and other methods are basically implemented by the proxy class _ARouter.

Complete
initialization , _ARouter.afterInit(); is called to complete the work after initialization.
It seems that we have to continue to dig deeper, and we enter the interior of _ARouter.init

In the spirit of getting to the bottom of things, I got into the LogisticsCenter.init again, I want to see how many layers it has and what does it do?

The above picture is a screenshot of my breakpoint debugging, so far we basically understand the work content of _ARouter.init:

First, ClassUtils scans the dex file to obtain the set of intermediate classes generated during compilation. This tool class does not look into it. Groups
according to Root, Interceptors, and Providers, traverses the intermediate classes returned in the previous step, completes the instantiation through reflection, and converts Routing metadata is stored in Warehouse.

Let's look at the inside of _ARouter.afterInit, this step is carried out after the completion of _ARouter.init


follow up

It can be clearly seen here that the InterceptorServiceImpl class that implements the InterceptorService interface is instantiated, and we will talk about the internal implementation of the interceptor later.
After the above steps, I believe everyone has a basic understanding. Let's sort out the initialization process:

1. The intermediate classes generated during compilation are initialized by the LogisticsCenter layer, grouped, and loaded into the memory cache Warehouse
2. Instantiate the interceptor

Now that we have understood what the initialization of ARouter does, let's take a look at what actions the standard routing request does. Since the implementation of ARouter is basically done by _ARouter, let's look directly at the corresponding method in _ARouter That's it.


Let's see what the build does:

1. According to the transmitted path information, separate the corresponding group group, and then call the overloaded method to return a Postcard (inherited from RouteMeta) object, which contains the routing information, such as the page I want to jump to, the logo of the startup , Activity entry and exit animation, and whether it needs to be intercepted and other information.
It assembles parameters (these parameters include basic types and common classes) through chain calls.
2. When Postcard assembles the parameters to be passed and other related information, it will call The navigation method begins to formally initiate a routing request

The navigation method inside Postcard is actually implemented by calling _ARouter, so we can directly look at the navigation in _ARouter, and enter _ARouter again to see which key actions the navigation has done. I drew the content inside the method. A rough flowchart to help understand

Based on the source code and flowchart, we can sort out the basic processing actions

1.LogisticsCenter.completion(postcard); process the incoming parameters, continue to execute down if successful, call the downgrade processing callback method if it fails, and continue to execute down
2. Determine whether the call needs to be intercepted, and call back if the interception is interrupted Interrupt the method, otherwise continue to execute the _navigation method, which is basically the last step.
3. Inside the _navigation, it will be processed according to the type in the Postcard. It will first wrap the Intent parameter, and then decide whether to use startActivityForResult or startActivity according to the requestCode. Jump to the corresponding Activity, and finally process the transition animation.

LogisticsCenter.completion(postcard) processing flow

Now the request process for building a standard route is generally clear, but there are still some points that I don't understand?

1. How are our parameters passed, and how is the serialization of ordinary entity class objects handled?
2. How are the parameters we pass into the target autowired?

So the next thing we need to focus on is the internal specific implementation. Let’s look at the first question first. We must know that the basic data types support serialization. How to pass our entity class objects to the past, the first thing we have to do is Implement the SerializationService interface yourself.

Yes, it's very clever. The official implementation class is JsonServiceImpl. In fact, it first converts the entity object into a json string, and then reverses it to the object when it reaches the routing target.

Now that the serialization of ordinary entity classes is clear, how to achieve automatic assembly when reaching the routing target? In fact, it is to call ARouter.getInstance().inject(this) in the target class; complete the injection

Still have to look inside the source code

It can be seen that when the inject method is called in the target class, the injection will be completed by obtaining the implementation class of the autowiring service AutowiredServiceImpl, and then entering AutowiredServiceImpl, the breakpoint view will be clearer. First, check whether there is a class marked with Autowired in the cache. If it does not exist, this class is instantiated by reflection xxx$$ARouter$$Autowired, and its inject method is called to pass in the target such as HomeActivity.

So next we have to enter xxx$$ARouter$$Autowiredthis class to see the situation. The
entered HomeActiivty$$ARouter$$Autowiredclass implements the inject method of the ISyringe interface. What this method does is to get the value in the Intent in the Activity (our inject method is actually called in onCreate). Of course, you can get the content of the Intent), and then assign it to the field marked with Autowired.

Direct assignment, there is wood! ! !
So, let's sort out the process

1. When a routing request is initiated, the parameters of the Postcard will be automatically packaged through LogisticsCenter.completion.
2. Then the data in the Postcard will be passed into the Intent to arouse the target Activity
3. The onCreate of the target Activity will call the inject method (automatic assembly processor Intermediate classes generated during compilation ( xxx$$ARouter$$Autowired, to complete assignment operations)

The following are the core entity classes

1. Postcard is a container that contains routing routes, runs through the entire routing request, and sets the parameters to be passed through chain calls, including common data types and Activity entry and exit animations and startup logos, similar to the role of a messenger
2.Warehouse The memory cache class, I also saw it when I analyzed it. When ARouter is initialized, it will load the intermediate classes generated during compilation through reflection. At this time, it is saved through Warehouse, and it caches several contents.

1.路由元数据
2.节点数据
3.拦截器数据

Is it over here? Through the analysis and flow chart just now, we have a basic understanding of the entire routing request process. It seems that we still missed a point, that is, jump interception! This is also one of the core functions of ARouter. It
intercepts the internal implementation principle and can compare the source code with the reference flow chart.

Official architecture diagram

Summary:
The source code design of the entire ARouter is still very clear, the internal design patterns are also very flexible, and the expansion of large-scale projects is very meticulous. The author's ability is limited. The author, download the latest source code 强烈推荐您on the above , debug and read, but the details of the Api in the latest ARouter source code part may change.GithubARouter

Reference:
https://yq.aliyun.com/articles/71687

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324480935&siteId=291194637