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

  1. If index overflows, an error is reported
  2. 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
  3. 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.