某车厂面试记录
自我介绍省略问导航服务厂商的方式是提供apk还是sdk答两种方案都有问贵司的导航方案对比高德百度或国外方案有什么优势吗答国内高德百度方案不是很了解我们是做海外的数据用的here引擎是自研的复盘没有说优势比如引擎自研不需要天天催引擎去修复问题功能支持定制化迭代速度快问你们导航apk被用于服务各家车厂厂商每个应该有差异化定制的你觉得各个厂商的最大差异在哪答一个是界面差异另外是功能方面比如某厂商有独有功能组队出行另外厂商需要路口放大图功能复盘没有提与车厂自有硬件和生态的整合。比如各个车厂车辆信号接口都是不同的问你们apk的整体架构方案答code基线一样不同厂商不同flavor问apk整体架构答两代引擎架构不同老引擎MVC新引擎mvvm新引擎使用新技术多如dagger解耦navigation界面跳转livedatadatabinding做界面动态刷新老引擎用JAVA开发新引擎使用Kotlin开发复盘没有说为什么有两代引擎为什么要转框架为什么使用新技术。比如MVC耦合性过高代码维护困难Navigation统一了跳转逻辑并且自动处理和保存返回栈状态不再使用原先那套晦涩难懂的flowmanager老引擎MVC中数据变化后需要手动findViewById然后setTextLiveData感知生命周期自动派发更新DataBinding把布局和数据绑定声明式写在一起减少很多UI模板代码问你们的老引擎用MVC架构那么界面和业务逻辑会耦合你们是如何解决的答xml界面也是按flavor切分出去问这样会不会工作量太大答项目初期是的问你们遇到的项目问题可能是项目共有的你们如何去在各个厂商里面都解决答我们用jira管理问题如果问题是各个平台都有那么会有public标签解决后其他项目组要么cherry pick要么rebase复盘没有回答到点子上公共问题我们只改基类。基类放在公共代码区不分厂商。改一次所有厂商自动生效不需要每个厂商单独去改。问你们的项目分flavor应该无法cherry pick吧答通过继承解决出问题的代码一般写在基类基类不分flavor复盘这里回答其实有问题之所以cherry pick是因为项目后期其实切出主分支了 在SOP上只能cherry pick其他项目共性问题问你们项目是只有一个activity多个fragment吗如何管理fragment答是的我们用自己开发的一套flowmanager管理fragmentfragment对应pagepage也有page startstopcreatedestroy等生命周期flowmanager内部维护一个stack界面跳转就是入栈出栈问如果fragment已经显示了你们的入栈效果是什么样的会弹出其他页面吗答不会出现你这样的问题如果界面已经显示flowID判断界面一样就不会跳转问如果不做界面跳转那么会做弹栈吗答有的方法会有的不会问有用到Android原生fragmentmanager管理fragment答没有复盘这块需要再研究一下代码问你对反射的理解答通过找方法找属性违规地调用系统方法去实现一个功能项目中只有一个地方用到反射是替换系统字体的相关代码。不推荐使用会影响性能除非没有其他解决方案。例如用反射和annotation可以实现IOC注解但是最新的dagger已经不使用反射实现注解了已经改为使用编译时生成代码不在运行时运行反射可以提高性能。问说说Kotlin的协程答轻量级线程对CPU资源开销小一个线程消耗资源大概1m协程大概只有十分之一或更少语法糖很厉害能够轻松实现多线程操作复盘回答不够精确Kotlin协程本质上是一个轻量级的线程框架它的核心是挂起与恢复机制。和传统线程相比资源开销小一个线程通常占用~1MB栈空间而协程可以小到几十字节所以一个进程可以轻松创建成千上万个协程。切换成本低协程的挂起是用户态操作不涉及操作系统内核调度比线程切换高效得多。语法糖用suspend关键字标记挂起函数配合launch、async等作用域构建器可以用同步的代码风格写出异步的逻辑避免传统的回调地狱。但要注意协程并不是为了取代线程而是更好地利用线程。它会把协程派发到有限的线程池上执行实现高效的并发。问协程里面加的日志没有打印有哪些可能情况答忘了复盘1. 协程根本没有被启动或执行launch或async的作用域被取消了比如在ViewModel中页面销毁时viewModelScope自动取消。协程被延迟启动start CoroutineStart.LAZY且没有被start()或await()触发。2. 日志所在的代码没有运行到协程内部有个空判断或条件分支日志所在的那条分支没进去。协程在到达日志前抛出了异常且异常被静默吞掉了没有打印堆栈。3. 日志所在的协程被取消或挂起未恢复在日志打印前调用了yield()或delay()而协程在此过程中被外部取消了。协程被挂起后一直没有恢复比如等待一个永远不会完成的CompletableDeferred。4. 日志本身的问题日志的Tag或级别被过滤了比如设置的是Log.d(VERBOSE)但手机当前日志级别是WARN。在非UI线程打印日志但使用的日志工具只绑定了主线程的日志输出较少见但有可能。问JAVA创建多线程的方式有哪两种他们有什么区别答只记得new threadrunable问其实是一个是用runable一个是继承thread方式复盘基础知识忘了继承 Thread 类创建一个类继承 Thread重写 run() 方法然后创建该类的实例并调用 start()。实现 Runnable 接口创建一个类实现 Runnable 接口实现 run() 方法然后将该实例作为参数传给 Thread 对象再调用 Thread 的 start()。核心区别3点扩展性Java是单继承继承Thread后就不能再继承其他类了而实现Runnable还可以继承其他类更灵活。资源共享多个Thread对象可以执行同一个Runnable实例天然适合共享同一份资源比如卖票系统继承Thread方式则需要用static变量更麻烦。代码分离Runnable方式把“任务本身”和“线程运行”分离更符合面向对象设计。问说说你项目中遇到的困难答举一个oom的例子截图投屏功能OOM。导航通过AIDL传输5Hz的图片给中间件期间发生OOM。调查下来发现allocateDirect方法会申请连续内存改用allocate可以申请非连续内存以避免OOM但是后续仍有OOM继续调查发现是因为我创建图片存储对象byte数组和Bitmap时每次都会new对象这个会造成内存抖动如果GC来不及释放内存那么最终会导致OOM。改法是做缓存不是每次都创建对象而是只有对象为空的时候才创建新的对象问你缓存的时候用到特殊对象么答没有缓存的时候就是将变量的声明从方法内移动到类里面比如创建的byte数组和bitmap对象的生命都是从方法内移动到类里面复盘这个回答没有理解面试官的意图。问“特殊对象”是在暗示直接缓存Bitmap和byte数组可能会持续占用大量内存导致其他问题。你应该回答的是如何控制缓存的大小和生命周期比如LRU缓存、软引用等。///TODO问你刚刚说的这个投屏功能和导航进程应该不是同一个进程吧你们是如何通信的为什么采用这个通信方式答不是同一个进程但是我们没有直接和副屏进程进行通信在系统框架中我们是将图片通过AIDL传输给中间件的这个方案是系统框架决定的客户要求我们用这样的方式进行通信。问你刚刚提到了Aidl 你认为Aidl发消息其内部是多线程还是单线程答单线程问其实是多线程Aidl内部会使用binder线程池进行消息的发送所以你如果不做处理消息可能乱序比如你发送的消息是1234收到的消息可能是3214你有做相关处理么答我们属于客户端单线程阻塞调用AIDL的sendIamge接口可以确保发送顺序和接收顺序问图片发送的时候需要进行序列化和反序列化你直到这是为什么么答可能是因为序列化后图片尺寸会变小吧问你对平台化的理解答底层通用比如地图引擎搜索求路等上层界面分flavor通过继承关系各个厂商特殊的定制部分为子类部分公共逻辑为基类。另外有特殊接口也可以通过adapter适配特殊接口问如何分析ANR答主要看ANR的日志在哪如果logcat日志没有就去anr下的trace文件看看实在没有就尝试复现混淆代码打印的堆栈信息可能会被加密这需要找到版本号对应的mapping文件去解析加密的方法具体是哪个方法。问ANR有哪一类这个ANR发生的条件是什么答activity fragment 应该是5s超时service是不是更长 10s或20s记不清了我们比较关注这个ANR如何产生和修复不是很关系具体需要花多久会造成ANR问你在ANR日志看到的main线程 最多的堆栈对应的哪一行日志对应到哪个方法答没有理解问题问单例如何写答Kotlin有object来写单例Java的话一般使用双重校验的单例使用前判断一次instance是否为空如果不为空那么返回实例如果为空那么加锁再判断一次然后创建实例问这种实现如果我用反射能不能绕开这个单例答不是很清楚问如果我不想外部用反射绕过这个单例应该怎么做答我们不是给外部提供sdk的所以这样的场景考虑地比较少问导航相当于一个服务可能连接很多客户端这时需要创建一个注册服务和一个反注册服务的接口这样的接口应该如何实现答不清楚问很多client端需要用到你的导航服务现在有一个request客户端注册了一个监听我们希望request不要阻塞原先的请求我希望拿到注册的监听随时给他一个返回答没有懂问正常的内存抖动不会造成OOM为什么你的之前AIDL传图片的例子会造成OOM答因为我创建的对象是图片图片没有压缩时尺寸比较大压缩后也有0.1M左右帧率又有5Hz如果内存紧张资源来不及释放就可能OOM问针对图片这种对象JVM是如何做回收的答在方法里面定义的对象在方法体结束后就相当于图里一个孤立的节点JVM在检测到对象没有可达路径时就会将对象回收问如何实现生产者消费者模式你会考虑什么方面答我不清楚生产者消费者如何实现但是我知道handler有用到生产者消费者模式例如hander的sendmsg相当于生产了一个对象looper在message队列中loop到msg然后执行handle msg时就是消费对象问你如何使用AI辅助工具答简单的基础知识有遗忘的问网页的AI这样回答比较迅速复杂的问题用GitHub copilot他能读取源码分析地不够到位但是AI不够智能可以AI和人工结对编程一起分析问题印证AI说的对不对问你有用AI工具做需求么如何做的答用提示词的方式做但是AI做可能有问题需要后期代码review问有什么问题么 略