美文网首页
DRouter的底层实现浅析

DRouter的底层实现浅析

作者: a_simple_coder | 来源:发表于2022-03-18 17:13 被阅读0次

    DRouter的底层实现浅析

    前言

    DRouter是滴滴乘客端自研的一套Android路由框架,基于平台化解耦的思想,为组件间通信服务。该项目以功能全面、易用为原则,支持各种路由场景,在页面路由、服务获取和过滤、跨进程及跨应用、VirtualApk插件支持等方面都能提供多样化的服务。目前已在滴滴乘客端、顺风车、单车、国际化、滴滴定制车中控、滴滴车载屏等十多个滴滴的app内使用,得到各种场景的验证。

    接入方式与使用

    接入

    github上的项目地址:https://github.com/didi/DRouter

    在项目根目录下的build.gradle下添加插件依赖:

    buildscript {
       dependencies {
        classpath "io.github.didi:drouter-plugin-proxy:1.0.1"
       }
    }
    

    在主module的build.gradle文件中应用插件:

    plugins {
      id 'com.didi.drouter'
    }
    

    在主modulebuild.gradle文件中的dependencies中添加依赖:

    dependencies {
      api "io.github.didi:drouter-api:2.2.1"
    }
    

    引入成功后,需要在Application中进行初始化:

    DRouter.init(application);
    

    使用方法

    这里只做简述,详情参考官方DRouter使用文档

    Activity、Fragment、View

    注册

    在Activity注册路由地址:

    // 多个路径导航到一个页面,使用正则表达式的或写法,
    // 比如:/test1|/test2|/test3,则在导航test1或test2或test3时都会跳到TestActivity1页面
    @Router(scheme =  "didi", host =  "router", path =  "/test1")
    class  TestActivity1  :  AppCompatActivity()
    
    发起页面跳转
    DRouter.build("didi://router/test1")
    .putExtra("tag",  this.javaClass.name)
    .start(this,  object  :  RouterCallback.ActivityCallback()  {
        // Activity回调
        override  fun  onActivityResult(resultCode:  Int,  data:  Intent?)  {
        }
    })
    

    Handler

    Handler的典型应用场景是:

    1. 端外、Push、h5调用native代码
    2. 无需下沉接口的组件化通信,有数据返回能力
    3. 实现增强版eventbus

    Handler支持静态和动态两种注册方式。

    静态注册
    @Router(scheme =  "didi", host =  "router", path =  "/sendOrder",
    thread =  Thread.WORKER)  //指定执行线程
    public  class  SendOrderHandler  implements  IRouterHandler  {
        @Override
        void  handle(@NonNull  Request request,  @NonNull  Result result){
            // result可以添加数据,会返回给调用方
            // 如果需要拦截后面的所有结点可以执行,默认不拦截
            request.getInterceptor().onInterrupt();
         }
    }
    
    动态定义和注册

    在内部注册一个监听者,不会重新实例化,类似EventBus,比EventBus增加了数据返回的能力 如果注册时使用了lifecycleOwner,会自动解注册

    // 动态注册`
    IRegister  register  = DRouter.register(RouterKey.build("/dynamic/handler").setLifecycleOwner(lifecycleOwner), new  IRouterHandler()  {
        @Override
        public  void  handle(@NonNull  Request request,  @NonNull  Result result)  {
        }
    });
    // 解注册,如果注册时使用了生命周期,则可省
    register.unregister();
    
    发起导航
    DRouter.build("didi://router/sendOrder")
    .setHoldTimeout(3000)  // 设置超时时间内未返回则自动回调callback
    .start(context,  new  RouterCallback()  {
        @Override
        public  void  onResult(@NonNull  Result result)  {
        // 只有目标被释放后才会回调,且不会阻塞该线程
        }
    });
    

    Hold

    正常情况下Activity被start后以及RouterHandler的handle方法执行完成后,RouterCallback中的Result会立刻返回,如果希望RouterCallback中的Result可以等待目标某个触发时机然后才返回Result,同时不阻塞当前线程,可以考虑暂存Result

    应用场景
    • 启动登录页,等待用户真正登陆成功后回调
    • 用户端外冷启动App,需要等待MainActivity的onResume回调或某些事情准备好后再回调
    • RouterHandler有耗时任务,希望等待执行完后再返回给调用方,又不阻塞调用方

    未使用hold参数时:

    @Router(path = "/activity/test2")
    public class ActivityTest2 extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_test_2);
    
            Request request = RouterHelper.getRequest(this);
            if (request != null) {
                TextView textView = findViewById(R.id.test2_text);
                textView.setText(String.format("BUILD_URI=%s\n\na=%s\nb=%s",
                        request.getUri().toString(),
                        request.getExtra().getString("a"),
                        request.getExtra().getString("b")));
            }
    
        }
    
        @Override
        protected void onResume() {
            super.onResume();
            RouterLogger.toast("ActivityTest2 执行onResume");
            long start = System.currentTimeMillis();
            new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
                @Override
                public void run() {
                    RouterLogger.toast(" 执行main线程");
                    RouterHelper.release(ActivityTest2.this);
                }
            }, 2000);
        }
    }
    
    

    发起导航:

    DRouter.build("/activity/test2")
            .putExtra("a", "我是a")
            .putExtra("b", "我是b")
            .start(this, new RouterCallback() {
                @Override
                public void onResult(@NonNull Result result) {
                    if (result.isActivityStarted()) {
                        RouterLogger.toast("ActivityTest2 打开成功,执行了回调");
                    }
                }
            });
    

    此时的执行顺序为:
    1、执行onResult回调:toast("ActivityTest2 打开成功,执行了回调");
    2、执行ActivityTest2的 onResume方法:toast("ActivityTest2 执行onResume");
    3、执行ActivityTest2的 onResume方法中的线程:toast(" 执行main线程")

    配置

    Activity或RouterHandler增加hold参数后,就启用了HoldResult

    异步Activity
    @Router(path = "/activity/test3", hold = true)
    public class ActivityTest3 extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_test_3);
    
            Request request = RouterHelper.getRequest(this);
            if (request != null) {
                TextView textView = findViewById(R.id.test3_text);
                textView.setText(String.format("BUILD_URI=%s\n\na=%s\nb=%s",
                        request.getUri().toString(),
                        request.getExtra().getString("a"),
                        request.getExtra().getString("b")));
            }
    
        }
    
        @Override
        protected void onResume() {
            super.onResume();
            RouterLogger.toast("ActivityTest3 执行onResume");
            new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
                @Override
                public void run() {
                    RouterLogger.toast(" 执行main线程");
                    RouterHelper.release(ActivityTest3.this);// 根据业务,在某个时间点触发这个释放(必须有)
                }
            }, 2000);
        }
    }
    
    
    异步RouterHandler
    @Router(path = "/handler/test3", hold = true, thread = Extend.Thread.WORKER)
    public class HandlerTest3 implements IRouterHandler {
        
        @Override
        public void handle(@NonNull final Request request, @NonNull final Result result) {
    
            RouterLogger.toast("HandlerTest3 执行handle");
            new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
                @Override
                public void run() {
                    RouterLogger.toast(" 执行main线程");
                    RouterHelper.release(request);
                }
            }, 2000);
        }
    }
    
    发起导航
    DRouter.build("/activity/test3")
            .putExtra("a", "我是a")
            .putExtra("b", "我是b")
            .start(this, new RouterCallback() {
                @Override
                public void onResult(@NonNull Result result) {
                    if (result.isActivityStarted()) {
                        RouterLogger.toast("hold ActivityTest3 打开成功,执行了回调");
                    }
                }
            });
    
    // 延迟1s返回结果,目标异步返回结束不阻塞当前线程
    DRouter.build("/handler/test3")
            .setLifecycleOwner(this)    //绑定生命周期,防止内存泄漏
            .setHoldTimeout(1000)   // 设置超时时间
            .start(this, new RouterCallback() {
                @Override
                public void onResult(@NonNull Result result) {
            // 只有目标被释放后才会回调,且不会阻塞该线程
                    RouterLogger.toast("HandlerTest3执行结束,回到回调的线程:" + Thread.currentThread().getName());
                }
            });
    

    此时的执行顺序为:
    1、执行ActivityTest3的 onResume方法:toast("ActivityTest3 执行onResume");
    2、执行ActivityTest3的 onResume方法中的线程:toast(" 执行main线程")
    3、执行onResult回调:toast("ActivityTest3 打开成功,执行了回调");

    Interceptor

    拦截器可以在打开指定页面时进行一些行为,比如:

    • 目标页面需要某种权限,比如某些场景下需要判断用户是否已登录
    • 目标页面需要先进行某项操作,比如打开定位功能
    定义拦截器

    全局拦截器是指任意请求都会执行,否则只执行指定的拦截器

    @Interceptor(name = "interceptor1",//可选,可以使用名字替代类耦合的方式来引用到
    priority = 0, //可选,优先级,值越大优先级越高,默认为0
    cache = Extend.Cache.SINGLETON, //可选,拦截器的缓存模式:NO、WEAK、SINGLETON 分别为不缓存、弱缓存、强缓存
    global = true)//可选,是否是全局拦截器,默认为false,相同priority的情况下,局部与全局拦截器按插入队列的顺序倒序执行
    public class GlobalInterceptor implements IRouterInterceptor {
    
        public GlobalInterceptor() {
            RouterLogger.getAppLogger().d("GlobalInterceptor create");
        }
    
        @Override
        public void handle(@NonNull final Request request) {
            if (request.getRouterType() == RouterType.ACTIVITY) {
            }
            request.getInterceptor().onContinue(); //必须要调,执行下一个拦截器,如果当前拦截器是最后一个,则打开路由的目标页面
        }
    }
    
    应用到页面
    @Router(scheme = "didi", host = "www\\.didi\\.com", path = "/activity/test2",interceptor =  GlobalInterceptor.class)
    public class ActivityTest2 extends AppCompatActivity {}
    

    源码分析

    初始化流程

    DRouter的初始化流程图.png

    上述为DRouter的初始化流程图,DRouter的项目结构为:

    • drouter-api:直接供业务层调用
    • drouter-api-stub:定义了MetaLoader和它的实现类,在编译期生成路由表代码
    • drouter-plugin:真正执行DRouter构建流程的插件,执行RouterTask去创建RouterLoader的真正实现并处理注解,加载路由表。
    • drouter-plugin-proxy:是一个Gradle Task,主要任务是拉取最新版本的drouter-plugin.jar包

    其中drouter-api是直接供业务层调用的module,在api module中,依赖了drouter-api-stub:

    compileOnly project(':drouter-api-stub')
    

    只在编译时有效,不会参与打包 可以在自己的moudle中使用该方式依赖一些比如com.android.support,gson这些使用者常用的库,避免冲突。

    drouter-api-stub中,定义了MetaLoader和它的实现类:RouterLoader、ServiceLoader和InterceptorLoader,而这些子类的方法都是空实现,在编译期,会通过javaassit API和Gradle Transform API来实现具体的方法。

    项目中直接引用的是drouter-plugin-proxy,根目录下的build.gradle中:

    classpath 'io.github.didi:drouter-plugin-proxy:1.0.1'
    

    drouter-plugin-proxy是一个Gradle Task,主要任务是拉取最新版本的drouter-plugin.jar包

    drouter-plugin内部是真正执行DRouter构建流程的插件,执行RouterTask去创建RouterLoader的真正实现并处理注解,加载路由表。

    所以DRouter的初始化,可以从编译和运行两个时期去分析。

    编译期

    通过Transform在项目编译过程中,在class编译为dex的过程中,能够获取到所有的class类,并进行处理。DRouter用到了groovy插件 + Transform API在编译期自动生成了路由表。首先,在drouter-plugin-proxy module中,创建了一个RouterPlugin:

    class RouterPlugin implements Plugin<Project> {
    
        @Override
        void apply(Project project) {
            ProxyUtil.confirm(project)
            project.extensions.create('drouter', RouterSetting)
            project.android.registerTransform(new TransformProxy(project))
        }
    }
    

    RouterPlugin最后注册了一个TransformProxy:

    class TransformProxy extends Transform {
        //...
    
        @Override
        void transform(TransformInvocation invocation) throws TransformException, InterruptedException, IOException {
            // 插件版本
            ProxyUtil.Logger.v("plugin proxy version: " + ProxyUtil.getProxyVersion())
            String pluginVersion = ProxyUtil.getPluginVersion(invocation)
            if (pluginVersion != null) {
                File pluginJar = new File(project.rootDir, ".gradle/drouter/drouter-plugin-${pluginVersion}.jar")
                if (!pluginJar.exists()) {// 若不存在,尝试下载
                    URL pluginUrl = new URL(String.format(HOST,
                            !ProxyUtil.isEmpty(project.drouter.repo) ?
                                    project.drouter.repo : "https://repo1.maven.org/maven2",
                            pluginVersion, pluginVersion))
                    try {
                        FileUtils.copyURLToFile(pluginUrl, pluginJar)
                        ProxyUtil.Logger.v("plugin url: " + pluginUrl.toString())
                        ProxyUtil.Logger.v("plugin download success: " + pluginJar.path)
                    } catch (Exception e) {
                        ProxyUtil.Logger.e("Error: drouter-plugin download fail, " + pluginUrl.toString())
                        throw e
                    }
                }
                if (pluginJar.exists()) {
                    URLClassLoader newLoader = new URLClassLoader([pluginJar.toURI().toURL()] as URL[], getClass().classLoader)
                    Class<?> transformClass = newLoader.loadClass("com.didi.drouter.plugin.RouterTransform") //【1】
                    ClassLoader threadLoader = Thread.currentThread().getContextClassLoader()
                    Thread.currentThread().setContextClassLoader(newLoader)
                    Constructor constructor = transformClass.getConstructor(Project.class)
                    Transform transform = (Transform) constructor.newInstance(project)
                    transform.transform(invocation)
                    Thread.currentThread().setContextClassLoader(threadLoader)
                    return
                } else {
                    ProxyUtil.Logger.e("Error: there is no drouter-plugin jar")
                }
            } else {
                ProxyUtil.Logger.e("Error: there is no drouter-plugin version")
            }
            copyFile(invocation)
        }
    }
    

    TransformProxy在下载最新的drouter-plugin插件,并在【1】处,创建了一个com.didi.drouter.plugin.RouterTransform对象,并执行了transform(invocation) ,查看RouterTransform.groovy的代码:

    class  RouterTransform  extends  Transform  {
        @Override
        void transform(TransformInvocation invocation) throws TransformException, InterruptedException, IOException {
            long timeStart = System.currentTimeMillis()
            this.setting = new RouterSetting.Parse(project.drouter)
            File cacheFile = new File(tmpDir, "cache")
            boolean configChanged = SystemUtil.configChanged(project, setting)
            boolean useCache = !isWindow && invocation.incremental && setting.cache && cacheFile.exists() && !configChanged
            Logger.v("DRouterTask start"
                    + " | incremental:" + invocation.incremental
                    + " | useCache:" + useCache)
            Logger.d(setting)
            if (useCache) {
                cachePathSet.addAll(cacheFile.readLines())
                Logger.v("read cache size: " + cachePathSet.size())
            }
            if (!invocation.incremental) {
                invocation.outputProvider.deleteAll()
            }
            compilePath = new ConcurrentLinkedQueue<>(project.android.bootClasspath)
            //先将原字节码copy到 dest,就可以实现编译期间干预字节码的目的
            for (TransformInput transformInput : invocation.inputs) {
                handleDirectory(invocation, transformInput)
                handleJar(invocation, transformInput)
            }
            //建立文件夹
            File dest = invocation.outputProvider.getContentLocation("DRouterTable", TransformManager.CONTENT_CLASS,
                    ImmutableSet.of(QualifiedContent.Scope.PROJECT), Format.DIRECTORY) // 【2】
            //groovy插件 操作dest 生成路由表类
            (new RouterTask(project, compilePath, cachePathSet, useCache, dest, tmpDir, setting, isWindow)).run() // 【3】
            FileUtils.writeLines(cacheFile, cachePathSet)
            Logger.v("Link: https://github.com/didi/DRouter")
            Logger.v("DRouterTask done, time used: " + (System.currentTimeMillis() - timeStart) / 1000f  + "s")
        }
    }
    
    

    【2】处创建了一个DRouterTable目录,供RouterTask使用,最终执行到【3】RouterTask的run方法:

        void run() {
            StoreUtil.clear();
            JarUtils.printVersion(project, compileClassPath);
            pool = new ClassPool();
            classClassify = new ClassClassify(pool, setting);
            startExecute();
        }
    
        private void startExecute() {
            try {
                long timeStart = System.currentTimeMillis();
                for (File file : compileClassPath) {
                    pool.appendClassPath(file.getAbsolutePath());
                }
                if (useCache) {
                    loadCachePaths(cachePathSet);
                } else {
                    loadFullPaths(compileClassPath);
                }
                Logger.d("load class used: " + (System.currentTimeMillis() - timeStart) + "ms");
                timeStart = System.currentTimeMillis();
                classClassify.generatorRouter(routerDir);  // 【4】
                Logger.d("generator router table used: " + (System.currentTimeMillis() - timeStart) + "ms");
                Logger.v("scan class size: " + count.get() + " | router class size: " + cachePathSet.size());
            } catch (Exception e) {
                JarUtils.check(e);
                String message = e.getMessage();
                if (message == null || !message.startsWith("Class:")) {
                    e.printStackTrace();
                }
                throw new GradleException("DRouter: Could not generate router table\n" + e.getMessage());
            } finally {
                executor.shutdown();
                FileUtils.deleteQuietly(wTmpDir);
            }
        }
    

    【4】处ClassClassify的generatorRouter方法:

       public void generatorRouter(File routerDir) throws Exception {
           for (int i = 0; i < classifies.size(); i++) {
               AbsRouterCollect cf = classifies.get(i);
               cf.generate(routerDir);
           }
       }
    
    

    AbsRouterCollect有三个实现类:

    • RouterCollect
    • InterceptorCollect
    • ServiceCollect

    ClassClassify在初始化时就添加了这三个:

    public class ClassClassify {
    
        private List<AbsRouterCollect> classifies = new ArrayList<>();
    
        public ClassClassify(ClassPool pool, RouterSetting.Parse setting) {
            classifies.add(new RouterCollect(pool, setting));
            classifies.add(new ServiceCollect(pool, setting));
            classifies.add(new InterceptorCollect(pool, setting));
        }
    // ...
    }
    

    这里以RouterCollect为例,RouterCollect的generate方法实现为:

    
        @Override
        public void generate(File routerDir) throws Exception {
            // 创建RouterLoader类
            CtClass ctClass = pool.makeClass(getPackageName() + ".RouterLoader");
            CtClass superClass = pool.get("com.didi.drouter.store.MetaLoader");
            ctClass.setSuperclass(superClass);
    
            StringBuilder builder = new StringBuilder();
            builder.append("public void load(java.util.Map data) {\n");
            for (CtClass routerCc : routerClass.values()) {
                try {
                    StringBuilder interceptorClass = null;
                    StringBuilder interceptorName = null;
    
                    String uriValue = "";
                    String schemeValue = "";
                    String hostValue = "";
                    String pathValue = "";
                    Annotation annotation = null;
                    String type;
                    int thread = 0;
                    int priority = 0;
                    boolean hold = false;
                    if (routerCc.hasAnnotation(Router.class)) {
                        uriValue = ((Router) routerCc.getAnnotation(Router.class)).uri();
                        schemeValue = ((Router) routerCc.getAnnotation(Router.class)).scheme();
                        hostValue = ((Router) routerCc.getAnnotation(Router.class)).host();
                        pathValue = ((Router) routerCc.getAnnotation(Router.class)).path();
                        thread = ((Router) routerCc.getAnnotation(Router.class)).thread();
                        priority = ((Router) routerCc.getAnnotation(Router.class)).priority();
                        hold = ((Router) routerCc.getAnnotation(Router.class)).hold();
                        annotation = getAnnotation(routerCc, Router.class);
                        if (checkSuper(routerCc, "android.app.Activity")) {
                            type = "com.didi.drouter.store.RouterMeta.ACTIVITY";
                        } else if (checkSuper(routerCc,
                                "android.support.v4.app.Fragment", "androidx.fragment.app.Fragment")) {
                            type = "com.didi.drouter.store.RouterMeta.FRAGMENT";
                        } else if (checkSuper(routerCc, "android.view.View")) {
                            type = "com.didi.drouter.store.RouterMeta.VIEW";
                        } else if (checkSuper(routerCc, "com.didi.drouter.router.IRouterHandler")) {
                            type = "com.didi.drouter.store.RouterMeta.HANDLER";
                        } else {
                            throw new Exception("@Router target class illegal, " +
                                    "support only Activity/Fragment/View/IRouterHandler");
                        }
                    } else {//如果没有Router注解时,直接取Class name
                        pathValue = "/" + routerCc.getName().replace(".", "/");
                        type = "com.didi.drouter.store.RouterMeta.ACTIVITY";
                    }
                    //省略...
                    boolean isAnyRegex = isRegex(schemeValue, hostValue, pathValue);
                    if (isAnyRegex) {
                        items.add("    put(\"" + uri + "\", " + metaBuilder + ", data); \n");
                        //builder.append("    put(\"").append(uri).append("\", ").append(metaBuilder).append(", data); \n");
                    } else {
                        items.add("    data.put(\"" + uri + "\", " + metaBuilder + "); \n");
                        //builder.append("    data.put(\"").append(uri).append("\", ").append(metaBuilder).append("); \n");
                    }
                    String duplicate = StoreUtil.insertUri(uri, routerCc);
                    if (duplicate != null) {
                        throw new Exception("\"" + uri + "\" on " + routerCc.getName() +
                                "\nhas duplication of name with class: " + duplicate);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                    throw new Exception("Class: === " + routerCc.getName() + " ===\nCause: " + e.getMessage());
                }
            }
            Collections.sort(items);
            for (String item : items) {
                builder.append(item);
            }
            builder.append("}");
    
            Logger.d("\nclass RouterLoader" + "\n" + builder.toString());
            //使用javassist将新类写入routerDir文件
            generatorClass(routerDir, ctClass, builder.toString());
        }
    
    从上面代码可以看出:Router中,只有Activity支持直接使用class的name直接导航(目标页面不能加router)。

    在项目主目录(一般是app, 这里用的是官方demo)下的demo/build/intermediates/transforms/DRouter/debug/com.didi.drouter.loader.host中查看生成的class类:

    //APP初始化时,会依次执行以下逻辑:
    // 1、DRouter.init(this);
    // 2、RouterStore.checkAndLoad(RouterStore.HOST, true);
    // 3、load(app);
    // 4、loadHostTable();
    // 5、new RouterLoader().load(routerMetas); 这个执行的就是已编译的RouterLoader类中的load方法进行生成路由表
    // 6、new InterceptorLoader().load(interceptorMetas);
    // 7、new ServiceLoader().load(serviceMetas);
    public class RouterLoader extends MetaLoader {
        @Override
        public void load(Map var1) { // 参数map 即为RouterStore.routerMetas
            //调用 RouterMeta.assembleRouter 将路由信息保存到 RouterMeta 中,以供调用
            var1.put("@@$$/activity/dynamic", RouterMeta.build(RouterMeta.ACTIVITY).assembleRouter("", "", "/activity/dynamic", "com.didi.demo.handler.DynamicActivity", (IRouterProxy)null, (Class[])null, (String[])null, 0, 0, false));
            var1.put("@@$$/activity/remote", RouterMeta.build(RouterMeta.ACTIVITY).assembleRouter("", "", "/activity/remote", "com.didi.demo.remote.RemoteActivity", (IRouterProxy)null, (Class[])null, (String[])null, 0, 0, false));
            var1.put("@@$$/activity/result", RouterMeta.build(RouterMeta.ACTIVITY).assembleRouter("", "", "/activity/result", "com.didi.demo.activity.ActivityResultActivity", (IRouterProxy)null, (Class[])null, (String[])null, 0, 0, false));
            var1.put("@@$$/activity/router_page_single", RouterMeta.build(RouterMeta.ACTIVITY).assembleRouter("", "", "/activity/router_page_single", "com.didi.demo.fragment.RouterPageSingleActivity", (IRouterProxy)null, (Class[])null, (String[])null, 0, 0, false));
            var1.put("@@$$/activity/router_page_stack", RouterMeta.build(RouterMeta.ACTIVITY).assembleRouter("", "", "/activity/router_page_stack", "com.didi.demo.fragment.RouterPageStackActivity", (IRouterProxy)null, (Class[])null, (String[])null, 0, 0, false));
            var1.put("@@$$/activity/router_page_viewpager", RouterMeta.build(RouterMeta.ACTIVITY).assembleRouter("", "", "/activity/router_page_viewpager", "com.didi.demo.fragment.RouterPageViewPagerActivity", (IRouterProxy)null, (Class[])null, (String[])null, 0, 0, false));
            var1.put("@@$$/activity/test3", RouterMeta.build(RouterMeta.ACTIVITY).assembleRouter("", "", "/activity/test3", "com.didi.demo.activity.ActivityTest3", (IRouterProxy)null, (Class[])null, (String[])null, 0, 0, true));
            var1.put("@@$$/activity/webview", RouterMeta.build(RouterMeta.ACTIVITY).assembleRouter("", "", "/activity/webview", "com.didi.demo.web.WebActivity", (IRouterProxy)null, (Class[])null, (String[])null, 0, 0, false));
            var1.put("@@$$/fragment/second", RouterMeta.build(RouterMeta.FRAGMENT).assembleRouter("", "", "/fragment/second", FragmentSecond.class, new com_didi_demo_fragment_FragmentSecond(), (Class[])null, (String[])null, 0, 0, false));
            var1.put("@@$$/handler/test1", RouterMeta.build(RouterMeta.HANDLER).assembleRouter("", "", "/handler/test1", HandlerTest1.class, new com_didi_demo_handler_HandlerTest1(), (Class[])null, (String[])null, 0, 1, false));
            var1.put("@@$$/handler/test3", RouterMeta.build(RouterMeta.HANDLER).assembleRouter("", "", "/handler/test3", HandlerTest3.class, new com_didi_demo_handler_HandlerTest3(), (Class[])null, (String[])null, 2, 0, true));
            var1.put("@@$$/view/bottom", RouterMeta.build(RouterMeta.VIEW).assembleRouter("", "", "/view/bottom", BottomView.class, new com_didi_demo_view_BottomView(), (Class[])null, (String[])null, 0, 0, false));
            var1.put("@@$$/view/headview", RouterMeta.build(RouterMeta.VIEW).assembleRouter("", "", "/view/headview", HeadView.class, new com_didi_demo_view_HeadView(), (Class[])null, (String[])null, 0, 0, false));
            var1.put("didi@@router$$/handler/test2", RouterMeta.build(RouterMeta.HANDLER).assembleRouter("didi", "router", "/handler/test2", HandlerTest2.class, new com_didi_demo_handler_HandlerTest2(), (Class[])null, (String[])null, 0, 0, false));
            this.put("@@$$/activity/Test1_<Arg1>_<Arg2>", RouterMeta.build(RouterMeta.ACTIVITY).assembleRouter("", "", "/activity/Test1_<Arg1>_<Arg2>", "com.didi.demo.activity.ActivityTest1", (IRouterProxy)null, new Class[]{InnerInterceptor.class}, new String[]{"interceptor1", "interceptor2"}, 0, 0, false), var1);
            this.put("@@$$/fragment/first/.*", RouterMeta.build(RouterMeta.FRAGMENT).assembleRouter("", "", "/fragment/first/.*", FragmentFirst.class, new com_didi_demo_fragment_FragmentFirst(), (Class[])null, (String[])null, 0, 0, false), var1);
            this.put("@@$$/handler/.*", RouterMeta.build(RouterMeta.HANDLER).assembleRouter("", "", "/handler/.*", HandlerAll.class, new com_didi_demo_handler_HandlerAll(), (Class[])null, (String[])null, 0, 2, false), var1);
            this.put("didi@@www\\.didi\\.com$$/activity/test2", RouterMeta.build(RouterMeta.ACTIVITY).assembleRouter("didi", "www\\.didi\\.com", "/activity/test2", "com.didi.demo.activity.ActivityTest2", (IRouterProxy)null, (Class[])null, (String[])null, 0, 0, false), var1);
        }
    
        public RouterLoader() {
        }
    }
    
    
    public class InterceptorLoader extends MetaLoader {
        @Override
        public void load(Map var1) {
            var1.put(GlobalInterceptor.class, RouterMeta.build(RouterMeta.INTERCEPTOR).assembleInterceptor(GlobalInterceptor.class, new com_didi_demo_interceptor_GlobalInterceptor(), 1, true, 0));
            var1.put(InterceptorTest1.class, RouterMeta.build(RouterMeta.INTERCEPTOR).assembleInterceptor(InterceptorTest1.class, new com_didi_demo_interceptor_InterceptorTest1(), 3, false, 0));
            var1.put("interceptor1", RouterMeta.build(RouterMeta.INTERCEPTOR).assembleInterceptor(InterceptorTest1.class, new com_didi_demo_interceptor_InterceptorTest1(), 3, false, 0));
            var1.put(InterceptorTest2.class, RouterMeta.build(RouterMeta.INTERCEPTOR).assembleInterceptor(InterceptorTest2.class, new com_didi_demo_interceptor_InterceptorTest2(), 2, false, 2));
            var1.put("interceptor2", RouterMeta.build(RouterMeta.INTERCEPTOR).assembleInterceptor(InterceptorTest2.class, new com_didi_demo_interceptor_InterceptorTest2(), 2, false, 2));
            var1.put(InnerInterceptor.class, RouterMeta.build(RouterMeta.INTERCEPTOR).assembleInterceptor(InnerInterceptor.class, new com.didi.drouter.proxy.com_didi_demo_interceptor_OutClass.InnerInterceptor(), 0, false, 0));
        }
    
        public InterceptorLoader() {
        }
    }
    
    
    public class ServiceLoader extends MetaLoader {
        @Override
        public void load(Map var1) {
            this.put(ServiceAny.class, RouterMeta.build(RouterMeta.SERVICE).assembleService(ServiceAny.class, new com_didi_demo_service_ServiceAny(), "name1", (IFeatureMatcher)null, 7, 0), var1);
            this.put(IRemoteFunction.class, RouterMeta.build(RouterMeta.SERVICE).assembleService(RemoteFunction.class, new com_didi_demo_remote_RemoteFunction(), "remote", new com_didi_demo_remote_RemoteFunction__RemoteFeature(), 0, 0), var1);
            this.put(IServiceTest.class, RouterMeta.build(RouterMeta.SERVICE).assembleService(ServiceAny.class, new com_didi_demo_service_ServiceAny(), "name1", (IFeatureMatcher)null, 7, 0), var1);
            this.put(IServiceTest.class, RouterMeta.build(RouterMeta.SERVICE).assembleService(ServiceTest1.class, new com_didi_demo_service_ServiceTest1(), "test1", (IFeatureMatcher)null, -8, 1), var1);
            this.put(IServiceTest.class, RouterMeta.build(RouterMeta.SERVICE).assembleService(ServiceTest2.class, new com_didi_demo_service_ServiceTest2(), "test2", new com_didi_demo_service_ServiceTest2__ServiceFeature(), 0, 0), var1);
            this.put(IServiceTest.class, RouterMeta.build(RouterMeta.SERVICE).assembleService(TestService.class, new com_didi_drouter_module_base_TestService(), "", (IFeatureMatcher)null, 0, 0), var1);
            this.put(IServiceTest2.class, RouterMeta.build(RouterMeta.SERVICE).assembleService(ServiceAny.class, new com_didi_demo_service_ServiceAny(), "name1", (IFeatureMatcher)null, 7, 0), var1);
            this.put(ICallService.class, RouterMeta.build(RouterMeta.SERVICE).assembleService(ServiceCallTest.class, new com_didi_demo_service_ServiceCallTest(), "login", (IFeatureMatcher)null, 0, 0), var1);
            this.put(Object.class, RouterMeta.build(RouterMeta.SERVICE).assembleService(ServiceAny.class, new com_didi_demo_service_ServiceAny(), "name1", (IFeatureMatcher)null, 7, 0), var1);
        }
    
        public ServiceLoader() {
        }
    }
    

    编译期对RouterLoader的load方法进行了修改,将带有注解的路由信息添加到了路由表中。

    运行期

    从DRouter的使用方法入手,我们首先看看DRouter在初始化的时候做了什么:

        public static void init(Application application) {
            SystemUtil.setApplication(application);// 将application储存到一个静态变量中
            RouterStore.checkAndLoad(RouterStore.HOST, true);// 【5】RouterStore.HOST = "host"
        }
    
    

    查看【5】部分的实现,进入RouterStore

        public static void checkAndLoad(final String app, boolean async) {
            if (!loadRecord.contains(app)) {
                synchronized (RouterStore.class) {
                    if (!loadRecord.contains(app)) {
                        loadRecord.add(app);
                        if (!async) {
                            Log.d(RouterLogger.NAME, "DRouter start load router table sync");
                            load(app);
                        } else {
                            new Thread("drouter-table-thread") {
                                @Override
                                public void run() {
                                    Log.d(RouterLogger.NAME, "DRouter start load router table in drouter-table-thread");
                                    load(app);
                                }
                            }.start();
                        }
                    }
                }
            }
        }
    
    

    参数 app是app唯一ID,若加载记录中已存在,则不会重新加载路由表;参数 async用来控制是同步还是异步加载路由表。真正的路由方法在RouterStoreload(app)中:

    // class RouterStore
        private static void load(String app) {
            long time = System.currentTimeMillis();
            boolean load;
            if (HOST.equals(app)) {//  HOST = ”host“
                load = loadHostTable();// 【6】
                initialized = true;
                latch.countDown();
            } else {
                // 【7】
                load = loadPluginTable(app,
                        Pair.create("Router", routerMetas),
                        Pair.create("Interceptor", interceptorMetas),
                        Pair.create("Service", serviceMetas));
            }
            if (!load) {
                RouterLogger.getCoreLogger().e(
                        "DRouterTable in app \"%s\" not found, " +
                                "please apply drouter plugin first.", app);
            }
    
            RouterLogger.getCoreLogger().d(
                    "[===DRouter load complete=== waste time: %sms]",
                    System.currentTimeMillis() - time);
        }
    

    当传入的参数 app等于HOST时,加载路由表的逻辑是loadHostTable(),若不相等,则是【7】处的方法。逐个分析:

        private static boolean loadHostTable() {
            try {
                new RouterLoader().load(routerMetas);
                new InterceptorLoader().load(interceptorMetas);
                new ServiceLoader().load(serviceMetas);
            }  catch (NoClassDefFoundError e) {
                return false;
            }
            return true;
        }
    

    另一种加载路由表的逻辑:

        private static boolean loadPluginTable(String packageName, Pair... targets) {
            try {
                for (Pair<String, Map<?, ?>> target : targets) {
                    // 通过反射构造MetaLoader
                    MetaLoader loader = (MetaLoader) ReflectUtil.getInstance(
                            Class.forName(String.format("com.didi.drouter.loader.%s.%sLoader",
                                    packageName, target.first))
                    );
                    assert loader != null;
                    loader.load(target.second);
                }
            } catch (ClassNotFoundException e) {
                return false;
            }
            return true;
        }
    

    两种方式最终都是调用了已编译的RouterLoaderInterceptorLoaderServiceLoader类中的load方法进行生成路由表,load方法在编译期已经将所有带有注解的内容自动生成到方法中了,整个DRouter初始化到此结束。

    动态添加路由表

    Handler支持动态添加路由表,动态加载和loadHostTable中用到的三个参数也有关系:

        // key is uriKey,value is meta, with dynamic
        // key is REGEX_ROUTER,value is map<uriKey, meta>
        private static final Map<String, Object> routerMetas = new ConcurrentHashMap<>();
        // key is interceptor impl or string name
        private static Map<Object, RouterMeta> interceptorMetas = new ConcurrentHashMap<>();
        // key is interface,value is set, with dynamic
        private static final Map<Class<?>, Set<RouterMeta>> serviceMetas = new ConcurrentHashMap<>();
    

    routerMetas的另一种添加在RouterStoreregister方法内:

        // 注册动态handler,key是routerKey,value是handler实例
        @NonNull
        @MainThread
        public synchronized static IRegister register(final RouterKey key, final IRouterHandler handler) {
            //...
           // 构建meta数据
            RouterMeta meta = RouterMeta.build(RouterMeta.HANDLER).assembleRouter(
                    key.uri.getScheme(), key.uri.getHost(), key.uri.getPath(),
                    (Class<?>) null, null, key.interceptor, key.interceptorName,
                    key.thread, key.priority, key.hold);
            meta.setDynamicHandler(handler);
            boolean success = false;
            String standardRouterKey = TextUtils.getStandardRouterKey(key.uri);
            // 若包含正则表达式或占位符
            if (meta.isRegexUri()) {
                Map<String, RouterMeta> regexMap = (Map<String, RouterMeta>) routerMetas.get(REGEX_ROUTER);
                if (regexMap == null) {
                    regexMap = new ConcurrentHashMap<>();
                    routerMetas.put(REGEX_ROUTER, regexMap);
                }
                RouterMeta exist = regexMap.get(standardRouterKey);
                if (exist == null || exist.isDynamic()) {
                    success = true;
                    regexMap.put(standardRouterKey, meta);
                }
            } else {
                RouterMeta exist = (RouterMeta) routerMetas.get(standardRouterKey);
                if (exist == null || exist.isDynamic()) {
                    success = true;
                    routerMetas.put(standardRouterKey, meta);
                }
            }
            // 绑定具有生命周期的对象销毁时,解除注册
            if (success && key.lifecycleOwner != null) {
                key.lifecycleOwner.getLifecycle().addObserver(new LifecycleObserver() {
                    @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
                    public void onDestroy() {
                        unregister(key, handler);
                    }
                });
            }
            RouterLogger.getCoreLogger().dw("register \"%s\" with handler \"%s\" %s",
                    !success,
                    TextUtils.getStandardRouterKey(key.uri),
                    handler.getClass().getName(),
                    success ? "success" : "fail");
            return new RouterRegister(key, handler);
        }
    

    serviceMetas的添加数据方法也是register,区别是支持泛型:

        // 注册动态服务,key是serviceKey,value是服务实例
        @NonNull
        @MainThread
        public synchronized static <T> IRegister register(final ServiceKey<T> key, final T service) {
             // ...
            RouterMeta meta = RouterMeta.build(RouterMeta.SERVICE).assembleService(
                    null, null,
                    key.alias, key.feature, key.priority, Extend.Cache.NO);
            meta.setDynamicService(service);
            key.meta = meta;
            Set<RouterMeta> metas = serviceMetas.get(key.function);
            if (metas == null) {
                metas = Collections.newSetFromMap(new ConcurrentHashMap<RouterMeta, Boolean>());
                serviceMetas.put(key.function, metas);
            }
            metas.add(meta);
            if (key.lifecycleOwner != null) {
                key.lifecycleOwner.getLifecycle().addObserver(new LifecycleObserver() {
                    @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
                    public void onDestroy() {
                        unregister(key, service);
                    }
                });
            }
            RouterLogger.getCoreLogger().d("register \"%s\" with service \"%s\" success, size:%s",
                    key.function.getName(), service, metas.size());
            return new RouterRegister(key, service);
        }
    

    interceptorMetas没有动态添加逻辑,因为拦截器和Activity/Fragment/View一样没有动态注册。

    调用流程

    调用方式为:

    DRouter.build(scheme).start(context);
    
    

    build方法:

        /**
         * Navigation to router
         * there will be only one activity match at most, but may be several router handler.
         * @param uri String
         * @return request
         */
        @NonNull
        public static Request build(String uri) {
            return Request.build(uri);
        }
    
    

    build方法返回了一个Request对象,查看Request.build(uri);的实现逻辑:

        public static Request build(String uri) {
            return new Request(uri == null ? Uri.EMPTY : Uri.parse(uri));
        }
    
    

    Request的构造方法为:

        private Request(@NonNull Uri uri) {
            this.uri = uri;
            this.serialNumber = String.valueOf(counter.getAndIncrement());
            putExtra(REQUEST_BUILD_URI, uri.toString());
        }
    
    

    然后再看看Request的start方法:

        public void start(Context context) {
            start(context, null);
        }
    
        /**
         * @param context If you want to return ActivityResult,
         *                please use Activity for context and ActivityCallback for RouterCallback.
         * @param callback Result to return.
         */
        public void start(Context context, RouterCallback callback) {
            this.context = context == null ? DRouter.getContext() : context;
            RouterLoader.build(this, callback).start(); //【8】
        }
    

    真正逻辑在【8】处,先看RouterLoader的build方法:

        @NonNull
        static RouterLoader build(Request request, RouterCallback callback) {
            RouterLoader loader = new RouterLoader();
            loader.primaryRequest = request; // 保存request
            loader.callback = callback; // 保存callback
            return loader;
        }
    

    RouterLoader的build方法返回了一个loader对象,看看它的start方法:

        void start() {
            if (!TextUtils.isEmpty(primaryRequest.authority)) {
                startRemote();
            } else {
                startLocal();
            }
        }
    

    根据request的authority属性是否为空来判断是远程还是本地调用,authority的值是远程进程的 ContentProvider 权限。可以在调用跳转逻辑时进行设置:

                DRouter.build("/handler/test1")
                        .putExtra("1", 1)
                        .putExtra("2", new Bundle())
                        .putAddition("3", new ParamObject())
                        .setRemoteAuthority("com.didi.drouter.remote.demo.host")
                        .start(DRouter.getContext());
    

    两个关键方法: startRemote 和 startLocal

    startLocal
        private void startLocal() {
            TextUtils.appendExtra(primaryRequest.getExtra(), TextUtils.getQuery(primaryRequest.getUri()));
            // 按顺序,优先级优先,然后完全匹配优先
            Map<Request, RouterMeta> requestMap = makeRequest();// 【9】
            if (requestMap.isEmpty()) {
                new Result(primaryRequest, null, callback);
                ResultAgent.release(primaryRequest, ResultAgent.STATE_NOT_FOUND);
                return;
            }
            final Result result = new Result(primaryRequest, requestMap.keySet(), callback);
            final boolean[] stopByRouterTarget = {false};
            for (final Map.Entry<Request, RouterMeta> entry : requestMap.entrySet()) {
                if (stopByRouterTarget[0]) {
                    // one by one
                    ResultAgent.release(entry.getKey(), ResultAgent.STATE_STOP_BY_ROUTER_TARGET);
                    continue;
                }
                // 拦截器优先处理,
                InterceptorHandler.handle(entry.getKey(), entry.getValue(), new IRouterInterceptor.IInterceptor() {
                    @Override
                    public void onContinue() {
                        entry.getKey().interceptor = new IRouterInterceptor.IInterceptor() {
                            @Override
                            public void onContinue() {
                            }
                            @Override
                            public void onInterrupt() {
                                stopByRouterTarget[0] = true;
                            }
                        };
                        // 【10】it will release branch auto when no hold or no target
                        RouterDispatcher.start(entry.getKey(), entry.getValue(), result, callback);
                        entry.getKey().interceptor = null;
                    }
    
                    @Override
                    public void onInterrupt() {
                        ResultAgent.release(entry.getKey(), ResultAgent.STATE_STOP_BY_INTERCEPTOR);
                    }
                });
            }
        }
    

    【9】将request按照顺序和优先级进行排序。

        @NonNull
        private Map<Request, RouterMeta> makeRequest() {
            Map<Request, RouterMeta> requestMap = new LinkedHashMap<>();
            // 从intent中获取序列化数据
            Parcelable parcelable = primaryRequest.getParcelable(Extend.START_ACTIVITY_VIA_INTENT);
            if (parcelable instanceof Intent) {
                primaryRequest.getExtra().remove(Extend.START_ACTIVITY_VIA_INTENT);// 删除额外信息
                Intent intent = (Intent) parcelable;
                PackageManager pm = primaryRequest.getContext().getPackageManager();
                List<ResolveInfo> activities = pm.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);//查找匹配的activities
                if (!activities.isEmpty()) {// 存在匹配的activity
                    primaryRequest.routerType = RouterType.ACTIVITY;
                    requestMap.put(this.primaryRequest, RouterMeta.build(RouterType.ACTIVITY).assembleRouter(intent));// 构建一个RouterMeta存入map
                }
            } else {
                List<RouterMeta> metas = getAllRouterMetas();// 获取所有的路由表信息
                int index = 0;
                for (RouterMeta routerMeta : metas) {// 开始遍历
                    // 将占位符键和值注入到捆绑包中
                    if (!routerMeta.injectPlaceHolder(primaryRequest.getUri(), primaryRequest.extra)) {
                        continue;
                    }
                    // 构建request
                    Request request = createBranchRequest(
                            this.primaryRequest, metas.size() > 1, routerMeta.getRouterType(), index++);
                    requestMap.put(request, routerMeta);
                }
            }
            return requestMap;
        }
    

    然后遍历request集合,去执行request的拦截器,执行InterceptorHandler.handle方法:

    
        static void handle(final Request request,
                                  RouterMeta meta,
                                  final IRouterInterceptor.IInterceptor callback) {
            RouterLogger.getCoreLogger().d(">> Enter request \"%s\" all interceptors", request.getNumber());
            Queue<IRouterInterceptor> interceptors = InterceptorLoader.load(meta);//加载拦截器
            handleNext(interceptors, request, callback);//执行拦截器
        }
    
    

    InterceptorLoader.load 方法如下:

        static @NonNull Queue<IRouterInterceptor> load(@NonNull RouterMeta meta) {
            Set<Class<? extends IRouterInterceptor>> allInterceptorClz = new ArraySet<>(globalInterceptor);//添加全局拦截器
            Class<? extends IRouterInterceptor>[] interceptors = meta.getInterceptors();//获取请求信息中的拦截器
            if (interceptors != null) {
                allInterceptorClz.addAll(Arrays.asList(interceptors));
            }
            String[] interceptorNames = meta.getInterceptorNames();
            if (interceptorNames != null) {
                for (String str : interceptorNames) {
                    allInterceptorClz.add(getInterceptorClz(str));
                }
            }
            Queue<IRouterInterceptor> result = new PriorityQueue<>(11, new InterceptorComparator());
            for (Class<? extends IRouterInterceptor> interceptorClass : allInterceptorClz) {
                result.add(getInstance(interceptorClass));//getInstance判断缓存中是否存在及是否加入缓存
            }
            return result;
        }
    
    

    然后看 handleNext 执行拦截器方法:interceptorMetas Map存储拦截器的格式为:var1.put(GlobalInterceptor.class, RouterMeta.build(RouterMeta.INTERCEPTOR).assembleInterceptor(GlobalInterceptor.class, new com_didi_demo_interceptor_GlobalInterceptor(), 1, true, 0));

        private static void handleNext(@NonNull final Queue<IRouterInterceptor> interceptors,
                                       final Request request,
                                       final IRouterInterceptor.IInterceptor callback) {
            final IRouterInterceptor interceptor = interceptors.poll();
            if (interceptor == null) {
                RouterLogger.getCoreLogger().d("<< Pass request \"%s\" all interceptors", request.getNumber());
                callback.onContinue();
                return;
            }
    
            RouterMeta interceptorMeta = RouterStore.getInterceptors().get(interceptor.getClass());//从 interceptorMetas 表中获取拦截器
            RouterLogger.getCoreLogger().d(
                    "interceptor \"%s\" execute, for request \"%s\", global:%s, priority:%s",
                    interceptor.getClass().getSimpleName(),
                    request.getNumber(),
                    interceptorMeta.isGlobal(),
                    interceptorMeta.getPriority());
            request.interceptor = new IRouterInterceptor.IInterceptor() {
    
                @Override
                public void onContinue() {
                    handleNext(interceptors, request, callback);//调下一个拦截器,需要在interceptor.handle中调用request.getInterceptor().onContinue();
                }
    
                @Override
                public void onInterrupt() {
                    RouterLogger.getCoreLogger().w("request \"%s\" interrupt by \"%s\"",
                            request.getNumber(), interceptor.getClass().getSimpleName());
                    callback.onInterrupt();
                }
            };
            interceptor.handle(request);//执行拦截操作
        }
    
    

    处理完后通过【10】RouterDispatcher进行分发:

    class RouterDispatcher {
    
        static void start(Request request, RouterMeta meta, Result result, RouterCallback callback) {
            switch (meta.getRouterType()) {
                case RouterType.ACTIVITY:
                    startActivity(request, meta, result, callback);
                    break;
                case RouterType.FRAGMENT:
                    startFragment(request, meta, result);
                    break;
                case RouterType.VIEW:
                    startView(request, meta, result);
                    break;
                case RouterType.HANDLER:
                    startHandler(request, meta, result, callback);
                    break;
                default:
                    break;
            }
        }
    }
    

    这里可以看出,只有Activity和handler支持callback,看下Activity:

    
        private static void startActivity(Request request, RouterMeta meta, Result result, RouterCallback callback) {
            Context context = request.getContext();
            Intent intent = meta.getIntent();
            if (intent == null) {
                intent = new Intent();
                Class<?> routerClass = meta.getRouterClass();
                // 如果有class优先使用class
                if (routerClass != null) {
                    intent.setClass(context, routerClass);
                } else {
                    intent.setClassName(context, meta.getActivityClassName());
                }
            }
            if (request.getExtra().containsKey(Extend.START_ACTIVITY_FLAGS)) {
                intent.setFlags(request.getInt(Extend.START_ACTIVITY_FLAGS));
            }
            if (!(context instanceof Activity)) {
                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            }
            intent.putExtra(ResultAgent.FIELD_START_ACTIVITY_REQUEST_NUMBER, request.getNumber());
            intent.putExtras(request.getExtra());
            boolean hasRequestCode = request.getExtra().containsKey(Extend.START_ACTIVITY_REQUEST_CODE);
            int requestCode = hasRequestCode? request.getInt(Extend.START_ACTIVITY_REQUEST_CODE) : 1024;
            if (context instanceof Activity && callback instanceof RouterCallback.ActivityCallback) { // 【11】
                ActivityCompat2.startActivityForResult((Activity) context, intent,
                        requestCode, (RouterCallback.ActivityCallback) callback);
            } else if (context instanceof Activity && hasRequestCode) { // 【12】
                ActivityCompat.startActivityForResult((Activity) context, intent,
                        requestCode, intent.getBundleExtra(Extend.START_ACTIVITY_OPTIONS));
            } else {  // 【13】
                ActivityCompat.startActivity(context, intent, intent.getBundleExtra(Extend.START_ACTIVITY_OPTIONS));
            }
            // 处理页面动画
            int[] anim = request.getIntArray(Extend.START_ACTIVITY_ANIMATION);
            if (context instanceof Activity && anim != null && anim.length == 2) {
                ((Activity) context).overridePendingTransition(anim[0], anim[1]);
            }
            result.isActivityStarted = true;
            // hold处理
            if (meta.isHold() && callback != null) {
                Monitor.startMonitor(request, result);// 【14】
            } else {
                ResultAgent.release(request, ResultAgent.STATE_COMPLETE);
            }
        }
    

    这里的【11】、【12】、【13】处,调用了不同的Activity启动方法,当callback的类型为RouterCallback.ActivityCallback时,通过自定义的工具类ActivityCompat2.startActivityForResult启动,而12、13则是调用系统的API直接startActivity:

        static void startActivityForResult(@NonNull final Activity activity,
                                           @NonNull final Intent intent, final int requestCode,
                                           RouterCallback.ActivityCallback callback) {
            final int cur = sCount.incrementAndGet();
            sCallbackMap.put(cur, new Pair<>(new WeakReference<>(activity), callback));
            final Active active;
            if (activity instanceof FragmentActivity) {// 创建一个Fragment,绑定到activity上
                active = new HolderFragmentV4();
            } else {
                active = new HolderFragment();
            }
            RouterLogger.getCoreLogger().d("HoldFragment start, put %s callback and page | isV4:",
                    cur, active instanceof HolderFragmentV4);
            active.getCompat().cur = cur;
            active.attach(activity, intent, requestCode); // 【15】
        }
    

    这里如果Activity是FragmentActivity,创建HolderFragmentV4,否则HolderFragment,两者都实现了Active接口,并调用了attach方法:

        public static class HolderFragmentV4 extends Fragment implements Active {
    
            @Override
            public void attach(Activity activity, Intent intent, int requestCode) {
                this.intent = intent;
                this.requestCode = requestCode;
                FragmentManager fragmentManager = ((FragmentActivity)activity).getSupportFragmentManager();
                FragmentTransaction transaction = fragmentManager.beginTransaction();
                transaction.add(this, TAG);
                transaction.commit();
            }
    }
    
        public static class HolderFragment extends android.app.Fragment implements Active {
    
            @Override
            public void attach(Activity activity, Intent intent, int requestCode) {
                this.intent = intent;
                this.requestCode = requestCode;
                android.app.FragmentManager fragmentManager = activity.getFragmentManager();
                android.app.FragmentTransaction transaction = fragmentManager.beginTransaction();
                transaction.add(this, TAG);
                transaction.commit();
            }
    }
    

    两个fragment类型的生命周期,都会调用ActivityCompat2的对应方法:

            @Override
            public void onCreate(@Nullable Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                activityCompat2.onCreate(savedInstanceState);
            }
    
            @Override
            public void onActivityResult(int requestCode, int resultCode, Intent data) {
                super.onActivityResult(requestCode, resultCode, data);
                activityCompat2.onActivityResult(getActivity(), resultCode, data);
            }
    
            @Override
            public void onSaveInstanceState(@NonNull Bundle outState) {
                super.onSaveInstanceState(outState);
                activityCompat2.onSaveInstanceState(outState);
            }
    
            @Override
            public void onDestroy() {
                super.onDestroy();
                activityCompat2.onDestroy();
            }
    

    当生命周期调用到了onActivityResult时,也会调用activityCompat2的onActivityResult方法,真正对callback进行调用:

    
        private void onActivityResult(Activity activity, int resultCode, Intent data) {
            RouterCallback.ActivityCallback cb;
            Pair<WeakReference<Activity>, RouterCallback.ActivityCallback> pair = sCallbackMap.get(cur);
            if (pair != null && (cb = pair.second) != null) {
                RouterLogger.getCoreLogger().d("HoldFragment ActivityResult callback success");
                cb.onActivityResult(resultCode, data);// 【16】callback进行了调用
            }
            if (pair == null || pair.first == null || pair.first.get() != activity) {
                RouterLogger.getCoreLogger().e("HoldFragment onActivityResult warn, " +
                        "for host activity changed, but still callback last host");
            }
            RouterLogger.getCoreLogger().d("HoldFragment remove %s callback and page", cur);
            sCallbackMap.remove(cur);
            active.remove();
        }
    

    【16】处对callback进行了调用。

    而【14】处的hold导致延迟执行callback,实际是通过一个handlerpostDelay消息来延时处理的:

    class Monitor {
    
        private static Handler timeoutHandler;
    
        static void startMonitor(final Request request, final Result result) {
            long period = request.holdTimeout;
            if (period > 0) {
                check();
                RouterLogger.getCoreLogger().d("monitor for request \"%s\" start, count down \"%sms\"",
                        request.getNumber(), period);
                timeoutHandler.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        RouterExecutor.submit(new Runnable() {
                            @Override
                            public void run() {
                                ResultAgent.release(request, ResultAgent.STATE_TIMEOUT);
                            }
                        });
                    }
                }, period);
            }
        }
    
        private static void check() {
            if (timeoutHandler == null) {
                synchronized (Monitor.class) {
                    if (timeoutHandler == null) {
                        HandlerThread handlerThread = new HandlerThread("timeout-monitor-thread");
                        handlerThread.start();
                        timeoutHandler = new Handler(handlerThread.getLooper());
                    }
                }
            }
        }
    }
    

    接下来是handler的实现:

    
        private static void startHandler(final Request request, final RouterMeta meta,
                                         final Result result, final RouterCallback callback) {
            // dynamic
            IRouterHandler handler = meta.getDynamicHandler();
            if (handler == null) {
                handler = meta.getRouterProxy() != null ?
                        (IRouterHandler) meta.getRouterProxy().newInstance(null) : null;
            }
            if (handler != null) {
                final IRouterHandler finalHandler = handler;
                RouterExecutor.execute(meta.getThread(), new Runnable() {
                    @Override
                    public void run() {
                        if (meta.isHold()) {
                            RouterLogger.getCoreLogger().w("request \"%s\" will hold", request.getNumber());
                        }
                        finalHandler.handle(request, result);
                        if (meta.isHold() && callback != null) {
                            Monitor.startMonitor(request, result);// 【17】 postDelay 延时调用
                        } else {
                            ResultAgent.release(request, ResultAgent.STATE_COMPLETE);// 【18】直接调用onResult
                        }
                    }
                });
            } else {
                ResultAgent.release(request, ResultAgent.STATE_ERROR);
            }
        }
    

    RouterExecutor是一个执行器,内部有一个线程池对象可以用于指定执行的线程。在runnable中,handler调用了handle方法,callback则是通过是否hold来判断是否立刻执行。

    在【18】处,为什么会立即执行callback:

    
        static void release(Request request, String reason) {
            if (request != null) {
                release(request.getNumber(), reason);
            }
        }
    
        // primary or branch.
        private synchronized static void release(String requestNumber, String reason) {
            Result result = getResult(requestNumber);
            if (result != null) {
                if (result.agent.primaryRequest.getNumber().equals(requestNumber)) {
                    // all clear
                    if (result.agent.branchRequestMap.size() > 1) {
                        RouterLogger.getCoreLogger().w(
                                "be careful, all request \"%s\" will be cleared", requestNumber);
                    }
                    for (String number : result.agent.branchRequestMap.keySet()) {
                        if (!result.agent.branchReasonMap.containsKey(number)) {
                            completeBranch(number, reason);
                        }
                    }
                } else {
                    // branch only
                    completeBranch(requestNumber, reason);
                }
                // check and release primary
                if (result.agent.branchReasonMap.size() == result.agent.branchRequestMap.size()) {
                    completePrimary(result);
                }
            }
        }
    

    这里的两个方法:

    completeBranch:

        private synchronized static void completeBranch(String branchNumber, String reason) {
            Result result = numberToResult.get(branchNumber);
            if (result != null) {
                if (STATE_TIMEOUT.equals(reason)) {// 超时强制执行log
                    RouterLogger.getCoreLogger().w(
                            "request \"%s\" time out and force-complete", branchNumber);
                }
                result.agent.branchReasonMap.put(branchNumber, reason);
                numberToResult.remove(branchNumber);
            }
        }
    

    completePrimary

    
        // finish
        private synchronized static void completePrimary(@NonNull Result result) {
            RouterLogger.getCoreLogger().d(
                    "primary request \"%s\" complete, router uri \"%s\", all reason %s",
                    result.agent.primaryRequest.getNumber(), result.agent.primaryRequest.getUri(),
                    result.agent.branchReasonMap.toString());
            numberToResult.remove(result.agent.primaryRequest.getNumber());
            if (result.agent.callback != null) {
                result.agent.callback.onResult(result);// 【19】callback得到调用
            }
            if (!numberToResult.containsKey(result.agent.primaryRequest.getNumber())) {
                RouterLogger.getCoreLogger().d(
                        "Request finish " +
                                "------------------------------------------------------------");
            }
        }
    

    最后再分析一下View和Fragment的启动:

        private static void startFragment(Request request, RouterMeta meta, Result result) {
            result.routerClass = meta.getRouterClass();
            if (request.getExtra().getBoolean(Extend.START_FRAGMENT_NEW_INSTANCE, true)) {
                Object object = meta.getRouterProxy() != null ?
                        meta.getRouterProxy().newInstance(null) : null;
                if (object instanceof Fragment) {
                    result.fragment = (Fragment) object;
                    result.fragment.setArguments(request.getExtra());
                }
            }
            ResultAgent.release(request, ResultAgent.STATE_COMPLETE);
        }
    
        private static void startView(Request request, RouterMeta meta, Result result) {
            result.routerClass = meta.getRouterClass();
            if (request.getExtra().getBoolean(Extend.START_VIEW_NEW_INSTANCE, true)) {
                Object object = meta.getRouterProxy() != null ?
                        meta.getRouterProxy().newInstance(request.getContext()) : null;
                if (object instanceof View) {
                    result.view = (View) object;
                    result.view.setTag(request.getExtra());
                }
            }
            ResultAgent.release(request, ResultAgent.STATE_COMPLETE);
        }
    

    View和Fragment的实现逻辑基本一致,创建一个对象保存到result中。

    最后是远程调用startRemote:

    
        private void startRemote() {
            Result result = new Result(primaryRequest, Collections.singleton(primaryRequest), callback);
            RemoteBridge.load(primaryRequest.authority, primaryRequest.resendStrategy,
                    primaryRequest.lifecycleOwner != null ? new WeakReference<>(primaryRequest.lifecycleOwner) : null)
                    .start(primaryRequest, result, callback);
        }
    

    RemoteBridge的load方法保存了远程调用的相关数据,start方法真正进行了调用:

    
        public void start(final Request request, final Result result, RouterCallback callback) {
            final RemoteCommand command = new RemoteCommand(RemoteCommand.REQUEST);
            command.bridge = RemoteBridge.this;
            command.resendStrategy = resendStrategy;
            command.lifecycle = lifecycle;
            command.uri = request.getUri().toString();
            command.extra = request.getExtra();
            command.addition = request.getAddition();
            if (callback != null) {
                command.binder = new IClientService.Stub() {
                    @Override
                    public RemoteResult callback(RemoteCommand resultCommand) {
                        RouterLogger.getCoreLogger().w("[Client] \"%s\" callback success", command);
    //                    result.setActivityStarted(resultCommand.isActivityStarted);
                        result.extra = resultCommand.extra;
                        result.addition = resultCommand.addition;
                        // callback once, so release it
                        RouterHelper.release(request);
                        return null;
                    }
                };
            } else {
                // no callback, so release immediately
                RouterHelper.release(request);
            }
            execute(command);
        }
    

    底层原理是binder跨进程调用。

    原文:https://www.wangt.cc/2021/12/drouter%E7%9A%84%E5%BA%95%E5%B1%82%E5%AE%9E%E7%8E%B0%E6%B5%85%E6%9E%90/

    相关文章

      网友评论

          本文标题:DRouter的底层实现浅析

          本文链接:https://www.haomeiwen.com/subject/ldjjrrtx.html