2024年安卓最新AutoRegister框架分析,美团三面面试什么

文末

当你打算跳槽的时候,应该把“跳槽成功后,我能学到什么东西?对我的未来发展有什么好处”放在第一位。这些东西才是真正引导你的关键。在跳槽之前尽量“物尽其用”,把手头上的工作做好,最好是完成了某个项目或是得到提升之后再走。跳槽不是目的,而是为了达到最终职业目标的手段

最后祝大家工作升职加薪,面试拿到心仪Offer


网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

AutoRegister.png

使用配置

AutoRegister项目app模块中配置代码如下:


apply plugin: 'auto-register'

project.ext.registerInfoList = [

    [

        'scanInterface'             : 'com.billy.app_lib_interface.ICategory'

        // scanSuperClasses 会自动被加入到exclude中,下面的exclude只作为演示,其实可以不用手动添加

        , 'scanSuperClasses'        : ['com.billy.android.autoregister.demo.BaseCategory']

        , 'codeInsertToClassName'   : 'com.billy.app_lib_interface.CategoryManager'

        //未指定codeInsertToMethodName,默认插入到static块中,故此处register必须为static方法

        , 'registerMethodName'      : 'register' //

        , 'exclude'                 : [

            //排除的类,支持正则表达式(包分隔符需要用/表示,不能用.)

            'com.billy.android.autoregister.demo.BaseCategory'.replaceAll('\.', '/') //排除这个基类

        ]

    ],

    [

        'scanInterface'             : 'com.billy.app_lib.IOther'

        , 'codeInsertToClassName'   : 'com.billy.app_lib.OtherManager'

        , 'codeInsertToMethodName'  : 'init' //非static方法

        , 'registerMethodName'      : 'registerOther' //非static方法

    ]

]



autoregister {

    registerInfo = registerInfoList

    cacheEnabled = true

} 



配置说明

上面配置代码中,AutoRegister通过autoregister闭包结构,映射参数配置。registerInfoList是一个配置列表,每个配置项都有固定的结构,插件通过结构中指定的参数,下面是配置数据在插件中对应的解析代码,可以看到_八个_配置:


void convertConfig() {

    registerInfo.each { map ->

        RegisterInfo info = new RegisterInfo()

        info.interfaceName = map.get('scanInterface')

        def superClasses = map.get('scanSuperClasses')

        if (!superClasses) {

            superClasses = new ArrayList<String>()

        } else if (superClasses instanceof String) {

            ArrayList<String> superList = new ArrayList<>()

            superList.add(superClasses)

            superClasses = superList

        }

        info.superClassNames = superClasses

        info.initClassName = map.get('codeInsertToClassName') //代码注入的类

        info.initMethodName = map.get('codeInsertToMethodName') //代码注入的方法(默认为static块)

        info.registerMethodName = map.get('registerMethodName') //生成的代码所调用的方法

        info.registerClassName = map.get('registerClassName') //注册方法所在的类

        info.include = map.get('include')

        info.exclude = map.get('exclude')

        info.init()

        if (info.validate())

            list.add(info)

        else {

            project.logger.error('auto register config error: scanInterface, codeInsertToClassName and registerMethodName should not be null\n' + info.toString())

        }

    }



    if (cacheEnabled) {

        checkRegisterInfo()

    } else {

        deleteFile(AutoRegisterHelper.getRegisterInfoCacheFile(project))

        deleteFile(AutoRegisterHelper.getRegisterCacheFile(project))

    }

} 



被收集的类配置:接口、基类及范围规定

scanInterface、scanSuperClasses、include、exclude,下面内容来自框架文档


> scanInterface : (必须)字符串,接口名(完整类名),所有直接实现此接口的类将会被收集

> scanSuperClasses : 字符串或字符串数组,类名(完整类名),所有直接继承此类的子类将会被收集

> include : 数组,需要扫描的类(正则表达式,包分隔符用/代替,如: com/billy/android/.*),默认为所有的类

> exclude : 数组,不需要扫描的类(正则表达式,包分隔符用/代替,如: com/billy/android/.*),列表项(正则)匹配到最终的实现类,指定基类/接口不会对其子类/实现类生效 



如下方法,确定扫描类列表,代码有删减:


class ScanClassVisitor extends ClassVisitor {

    

    void visit(int version, int access, String name, String signature,

               String superName, String[] interfaces) {

        super.visit(version, access, name, signature, superName, interfaces)

        //抽象类、接口、非public等类无法调用其无参构造方法

        if (is(access, Opcodes.ACC_ABSTRACT)

                || is(access, Opcodes.ACC_INTERFACE)

                || !is(access, Opcodes.ACC_PUBLIC)

        ) {

            return

        }

        infoList.each { ext ->

            if (shouldProcessThisClassForRegister(ext, name)) {

                if (superName != 'java/lang/Object' && !ext.superClassNames.isEmpty()) {

                    for (int i = 0; i < ext.superClassNames.size(); i++) {

                        if (ext.superClassNames.get(i) == superName) {

                            //  println("superClassNames--------"+name)

                            ext.classList.add(name) //需要把对象注入到管理类 就是fileContainsInitClass

                            found = true

                            addToCacheMap(superName, name, filePath)

                            return

                        }

                    }

                }

                if (ext.interfaceName && interfaces != null) {

                    interfaces.each { itName ->

                        if (itName == ext.interfaceName) {

                            ext.classList.add(name)//需要把对象注入到管理类  就是fileContainsInitClass

                            addToCacheMap(itName, name, filePath)

                            found = true

                        }

                    }

                }

            }

        }

    }

}



// include和exclude的处理,exclude的优先级高于include

private static boolean shouldProcessThisClassForRegister(RegisterInfo info, String entryName) {

    if (info != null) {

        def list = info.includePatterns

        if (list) {

            def exlist = info.excludePatterns

            Pattern pattern, p

            for (int i = 0; i < list.size(); i++) {

                pattern = (Pattern)list.get(i)

                if (pattern.matcher(entryName).matches()) {

                    if (exlist) {

                        for (int j = 0; j < exlist.size(); j++) {

                            p = (Pattern)exlist.get(j)

                            if (p.matcher(entryName).matches())

                                return false

                        }

                    }

                    return true

                }

            }

        }

    }

    return false

} 



管理和注册方法设置

> codeInsertToClassName : (必须)字符串,类名(完整类名),通过编译时生成代码的方式将收集到的类注册到此类的codeInsertToMethodName方法中

> codeInsertToMethodName: 字符串,方法名,注册代码将插入到此方法中。若未指定,则默认为static块,(方法名为:)

> registerClassName: 无

> registerMethodName : (必须)字符串,方法名,静态方法,方法的参数为 scanInterface 



参数分为两组:codeInsertToClassName / codeInsertToMethodNameregisterMethodName / registerClassName

  1. 第一组是管理类和管理方法:对应到示例中是 CategoryManager#initCategory

  2. 第二组是注册类和注册方法:对应到示例中是 CategoryManager#register

示例中没有明确指定registerClassName,会默认赋值initClassName,也就是 codeInsertToClassName。所以,框架的设置中允许把管理类和注册类分开来写的。


// 代码有删减

void convertConfig() {

    registerInfo.each { map ->

        RegisterInfo info = new RegisterInfo()

        info.initClassName = map.get('codeInsertToClassName')    //代码注入的类

        info.initMethodName = map.get('codeInsertToMethodName')  //代码注入的方法(默认为static块)

        info.registerMethodName = map.get('registerMethodName')  //生成的代码所调用的方法

        info.registerClassName = map.get('registerClassName')    //注册方法所在的类

        info.init()

    }

}



void init() {

    if (!registerClassName) {

        registerClassName = initClassName

    }

} 



注释:从示例中可以看出 codeInsertToMethodNameregisterMethodName 需要保持一致,同时为静态方法或者同时非静态方法;如果没有指定codeInsertToMethodName,默认是静态代码块,视为静态方法,此时 registerMethodName 需指定静态方法。

对于四个参数的解释,参考框架中的实现类,略有修改。从下面的代码可以看出,AutoRegister的主要作用是从不同的模块收集子类和实现类(CategoryA/CategoryB),生成注册函数(register)调用代码,插入到初始化入口函数 initCategory()static 代码块。在此基础上,APP初始化时只需要调用 initCategory() 或者自动执行 static 代码块,就可以做到添加一系列实例对象到初始化列表(CATEGORIES)中,完成注册工作。


// codeInsertToClassName | registerClassName

public class CategoryManager {

    private static final HashMap<String, ICategory> CATEGORIES = new HashMap<>();



    // 不指定 codeInsertToMethodName 时生效

    static {

        register(new CategoryA()); //scanInterface的实现类

        register(new CategoryB()); //scanSuperClass的子类

    }



    // codeInsertToMethodName

    public static void initCategory() {

        register(new CategoryA()); //scanInterface的实现类

        register(new CategoryB()); //scanSuperClass的子类

    }



    // registerMethodName

    static void register(ICategory category) {

        if (category != null) {

            CATEGORIES.put(category.getName(), category);

        }

    }



    public static Set<String> getCategoryNames() {

        return CATEGORIES.keySet();

    }

} 






ory) {

        if (category != null) {

            CATEGORIES.put(category.getName(), category);

        }

    }



    public static Set<String> getCategoryNames() {

        return CATEGORIES.keySet();

    }

} 





总结:

各行各样都会淘汰一些能力差的,不仅仅是IT这个行业,所以,不要被程序猿是吃青春饭等等这类话题所吓倒,也不要觉得,找到一份工作,就享受安逸的生活,你在安逸的同时,别人正在奋力的向前跑,这样与别人的差距也就会越来越遥远,加油,希望,我们每一个人,成为更好的自己。

  • BAT大厂面试题、独家面试工具包,

  • 资料包括 数据结构、Kotlin、计算机网络、Framework源码、数据结构与算法、小程序、NDK、Flutter,


网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

仅是IT这个行业,所以,不要被程序猿是吃青春饭等等这类话题所吓倒,也不要觉得,找到一份工作,就享受安逸的生活,你在安逸的同时,别人正在奋力的向前跑,这样与别人的差距也就会越来越遥远,加油,希望,我们每一个人,成为更好的自己。

  • BAT大厂面试题、独家面试工具包,

  • 资料包括 数据结构、Kotlin、计算机网络、Framework源码、数据结构与算法、小程序、NDK、Flutter,

    [外链图片转存中…(img-hpkuTn4j-1715814595688)]
    [外链图片转存中…(img-e5nSqMHH-1715814595688)]

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 17
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值