preface
In the previous part, we introduced the use of APT in the Router framework, which collects routing information through annotation processor. In this part, we will talk about the operating mechanism of Router.
Why use interceptors?
Let’s first look at the routing usage scenarios
When the server sends a link, we first need to determine whether the link is in the routing table. If so, we need to obtain the corresponding page information. Otherwise, we need to determine whether the link supports the opening of the built-in browser, and finally obtain the target page after layer upon layer filtering. This might involve inserting some generic parameters, but does it feel like an OkHttp web request?
With interceptors, we can freely insert some custom logic to make our routing more flexible.
Principle of interceptor
Let’s start with a call diagram
Citing the juejin. Cn/post / 684490…
Interceptors are similar to The Android Touch mechanism, except that interceptors can terminate the chain call directly and return the result, whereas touch events must pass through layers and return.
The implementation of interceptor layer invocation is mainly through the Chain call
interface Interceptor {
fun intercept(chain: Chain): Response
interface Chain {
fun request(): Request
fun proceed(request: Request): Response
fun call(): Call
}
}
Copy the code
Note: Some methods are omitted here
The interceptor needs to implement the Intercept method, providing a chain argument
The request method in the Chain retrieves the request entity, returns a Response directly based on the request information, or passes the request to the next interceptor using the PROCEED method.
Let’s look at the implementation of Chain
class RealInterceptorChain( private val interceptors: List<Interceptor>, private val index: Int, private val request: Request, private val call: Call ) : Interceptor.Chain { private var calls: Int = 0 override fun call(): Call { return call } override fun request(): Request { return request } override fun proceed(request: Request): Response { if (index >= interceptors.size) throw AssertionError() calls++ // Call the next interceptor in the chain. val next = RealInterceptorChain(interceptors, index + 1, request, call) val interceptor = interceptors[index] val response = interceptor.intercept(next) // Confirm that the next interceptor made its required call to chain.proceed(). if (response == null && index + 1 < interceptors.size && next.calls ! = 1) { throw IllegalStateException("router interceptor " + interceptor + " must call proceed() exactly once") } // Confirm that the intercepted response isn't null. if (response == null) { throw NullPointerException("interceptor $interceptor returned null") } return response } }Copy the code
Note: Some code is omitted here
Constructor:
- Interceptors A collection of all connectors
- Index Indicates the execution number of the interceptor
- Request Request entity
- Call request executor
The logic is mostly in the proceed method
- If index overflows, an error is reported
- Index + 1 is then used to construct the next call chain, which executes the interception request. This is where you can do a chain loop call
- Finally, check the result and return the final result
Chain calls are implemented in a few lines of code, that’s all.
The source code
View the source code
conclusion
This article mainly introduces the implementation principle of interceptor, hope to help you.