这是我这么多次京东面试中印象最深刻的一次,很难受,也不知道谁有这种感受,一面过了,二面15号但是15学校考试 冲突了.
突然在12号下午收到短信去上海面试(本人广西 飞机3小时 ).于是13从冲冲去订机票,13号一早订机票 到14晚上1点到(晚上10点机票 因为钱少),我完全没去过上海,下飞机一直不知道出口在哪...然后一个黑车司机问我要不要住店 和打车.我没理他 ,一直纠缠我..... 然后看到工作人员说出租车在那边出去...... 然后再美团订了个酒店 然后打车过去了.车费80心疼 我真农村的.... 到酒店晚上3点了.我发现我简历没有做于是做简历,到晚上5点,睡到6点.然后出去上海鹿角嘴酒店 .我这边在郊区必须早去 市区酒店有些贵.
到酒店 一楼有个电视提示 面试在3楼,到了之后扫码签到.收到短信说道XXX面试官面试.后面就是大家关心的面试内容
5分钟自我介绍 ,面试官看简历,我说"我是一个专升本 的同学,也许学历在京东中是最低的了.(面试官 说不 你很好 很亲切) ,然后我就说我在北京工作一年 的事情,我们公司CTO是北京邮电大学教授,
在贝尔实验室工作过 ,经常受他指导.做过3个商业项目 XXXX,YYYYY,ZZZZ. 还有一个自己无聊做的漫画软件,接口数据抓取其他漫画app.还有xposed 模块开发小米商城秒杀商品,和超星尔雅app 破解刷课,
学校的教务抢课脚本"
然后面试官叫我 选择一个 你自己影响最大的项目,我选择了xposed 破解超星尔雅刷课视频.提到了xposed原理,还有提到了免注册启动activity 原理,涉及handler原理(这里我扩张到ActivityThread,threadLoal 一些其他知识) activity启动原理 ,aidl原理.这里我就不写我怎么回答了(我想涉及到jadx和smai,动态调试 没机会了).
然后面试官就问我 消息推送,这一块对于想进bat的同学不难吧(反正腾讯 和阿里我挂了).消息推送无非两种 push 和pull ,一种是一直循环 拉取,一种是长连接(xmpp.xqtt),因为xmpp由于信息载体过大 所以我选择xqtt的应用层协议.
.....这里说就点长了略过...... 关键是app包活才是关键(我涉及到native,双service,gcm,alermanage,jobscheuler,心跳同步....).
然后面试官就说 我没什么问题 你有什么想问的.
我就跟他说15号考试,能不能申请电话面试,他真的很和蔼说帮我问问,后来第二天下午查官网面试状态变成复试中 ,但是没有收到短信和邮件.很难受.应该就这样结束了!
上述面试题已经整理成文档,有需要的可以 点击进入 查看领取资料。
1、描述一下Android数据持久存储方式?
参考回答:Android平台实现数据持久存储的常见几种方式:
SharedPreferences存储:一种轻型的数据存储方式,本质是基于XML文件存储的key-value键值对数据,通常用来存储一些简单的配置信息(如应用程序的各种配置信息);
SQLite数据库存储:一种轻量级嵌入式数据库引擎,它的运算速度非常快,占用资源很少,常用来存储大量复杂的关系数据;
ContentProvider:四大组件之一,用于数据的存储和共享,不仅可以让不同应用程序之间进行数据共享,还可以选择只对哪一部分数据进行共享,可保证程序中的隐私数据不会有泄漏风险;
File文件存储:写入和读取文件的方法和 Java中实现I/O的程序一样;
网络存储:主要在远程的服务器中存储相关数据,用户操作的相关数据可以同步到服务器上;
2、SharedPreferences的应用场景?注意事项?
参考回答:SharedPreferences是一种轻型的数据存储方式,本质是基于XML文件存储的key-value键值对数据,通常用来存储一些简单的配置信息,如int,String,boolean、float和long;
注意事项:
勿存储大型复杂数据,这会引起内存GC、阻塞主线程使页面卡顿产生ANR
勿在多进程模式下,操作Sp
不要多次edit和apply,尽量批量修改一次提交
建议apply,少用commit
3、SharedPrefrences的apply和commit有什么区别?
参考回答:apply没有返回值而commit返回boolean表明修改是否提交成功。
apply是将修改数据原子提交到内存, 而后异步真正提交到硬件磁盘, 而commit是同步的提交到硬件磁盘,因此,在多个并发的提交commit的时候,他们会等待正在处理的commit保存到磁盘后在操作,从而降低了效率。而apply只是原子的提交到内容,后面有调用apply的函数的将会直接覆盖前面的内存数据,这样从一定程度上提高了很多效率。
apply方法不会提示任何失败的提示。由于在一个进程中,sharedPreference是单实例,一般不会出现并发冲突,如果对提交的结果不关心的话,建议使用apply,当然需要确保提交成功且有后续操作的话,还是需要用commit的。
4、了解SQLite中的事务操作吗?是如何做的
参考回答:SQLite在做CRDU操作时都默认开启了事务,然后把SQL语句翻译成对应的SQLiteStatement并调用其相应的CRUD方法,此时整个操作还是在rollback journal这个临时文件上进行,只有操作顺利完成才会更新db数据库,否则会被回滚;
5、使用SQLite做批量操作有什么好的方法吗?
参考回答:使用SQLiteDatabase的beginTransaction方法开启一个事务,将批量操作SQL语句转化为SQLiteStatement并进行批量操作,结束后endTransaction()
6、如何删除SQLite中表的个别字段
参考回答:SQLite数据库只允许增加字段而不允许修改和删除表字段,只能创建新表保留原有字段,删除原表
7、使用SQLite时会有哪些优化操作?
使用事务做批量操作及时关闭Cursor,避免内存泄露耗时操作异步化:数据库的操作属于本地IO耗时操作,建议放入异步线程中处理ContentValues的容量调整:ContentValues内部采用HashMap来存储Key-Value数据,ContentValues初始容量为8,扩容时翻倍。因此建议对ContentValues填入的内容进行估量,设置合理的初始化容量,减少不必要的内部扩容操作使用索引加快检索速度:对于查询操作量级较大、业务对查询要求较高的推荐使用索引1、Android中进程和线程的关系?区别?
线程是CPU调度的最小单元,同时线程是一种有限的系统资源进程一般指一个执行单元,在PC和移动设备上一个程序或者一个应用一般来说,一个App程序至少有一个进程,一个进程至少有一个线程(包含与被包含的关系),通俗来讲就是,在App这个工厂里面有一个进程,线程就是里面的生产线,但主线程(主生产线)只有一条,而子线程(副生产线)可以有多个进程有自己独立的地址空间,而进程中的线程共享此地址空间,都可以并发执行
2、如何开启多进程 ?应用是否可以开启N个进程 ?
在AndroidMenifest中给四大组件指定属性android:process开启多进程模式
在内存允许的条件下可以开启N个进程
3、为何需要IPC?多进程通信可能会出现的问题?
参考回答:所有运行在不同进程的四大组件(Activity、Service、Receiver、ContentProvider)共享数据都会失败,这是由于Android为每个应用分配了独立的虚拟机,不同的虚拟机在内存分配上有不同的地址空间,这会导致在不同的虚拟机中访问同一个类的对象会产生多份副本。比如常用例子(通过开启多进程获取更大内存空间、两个或者多个应用之间共享数据、微信全家桶)
一般来说,使用多进程通信会造成如下几方面的问题:
静态成员和单例模式完全失效:独立的虚拟机造成线程同步机制完全实效:独立的虚拟机造成SharedPreferences的可靠性下降:这是因为Sp不支持两个进程并发进行读写,有一定几率导致数据丢失Application会多次创建:Android系统在创建新的进程会分配独立的虚拟机,所以这个过程其实就是启动一个应用的过程,自然也会创建新的Application
4、Android中IPC方式、各种方式优缺点,为什么选择Binder?
参考回答:
与Linux上传统的IPC机制,比如System V,Socket相比,Binder好在哪呢?
传输效率高、可操作性强:传输效率主要影响因素是内存拷贝的次数,拷贝次数越少,传输速率越高。从Android进程架构角度分析:对于消息队列、Socket和管道来说,数据先从发送方的缓存区拷贝到内核开辟的缓存区中,再从内核缓存区拷贝到接收方的缓存区,一共两次拷贝,如图:
而对于Binder来说,数据从发送方的缓存区拷贝到内核的缓存区,而接收方的缓存区与内核的缓存区是映射到同一块物理地址的,节省了一次数据拷贝的过程,如图:
由于共享内存操作复杂,综合来看,Binder的传输效率是最好的。
实现C/S架构方便:Linux的IPC方式除了Socket以外都不是基于C/S架构,而Socket主要用于网络间的通信且传输效率较低。Binder基于C/S架构 ,Server端与Client端相对独立,稳定性较好。
安全性高:传统Linux IPC的接收方无法获得对方进程可靠的UID/PID,从而无法鉴别对方身份;而Binder机制为每个进程分配了UID/PID且在Binder通信时会根据UID/PID进行有效性检测。
5、Binder机制的作用和原理?
参考回答:Linux系统将一个进程分为用户空间和内核空间。对于进程之间来说,用户空间的数据不可共享,内核空间的数据可共享,为了保证安全性和独立性,一个进程不能直接操作或者访问另一个进程,即Android的进程是相互独立、隔离的,这就需要跨进程之间的数据通信方式。
一次完整的 Binder IPC 通信过程通常是这样:
首先 Binder 驱动在内核空间创建一个数据接收缓存区;
接着在内核空间开辟一块内核缓存区,建立内核缓存区和内核中数据接收缓存区之间的映射关系,以及内核中数据接收缓存区和接收进程用户空间地址的映射关系;
发送方进程通过系统调用 copyfromuser() 将数据 copy 到内核中的内核缓存区,由于内核缓存区和接收进程的用户空间存在内存映射,因此也就相当于把数据发送到了接收进程的用户空间,这样便完成了一次进程间的通信。
6、Binder框架中ServiceManager的作用?
参考回答:Binder框架 是基于 C/S 架构的。由一系列的组件组成,包括 Client、Server、ServiceManager、Binder驱动,其中 Client、Server、Service Manager 运行在用户空间,Binder 驱动运行在内核空间
Server&Client:服务器&客户端。在Binder驱动和Service Manager提供的基础设施上,进行Client-Server之间的通信。
ServiceManager(如同DNS域名服务器)服务的管理者,将Binder名字转换为Client中对该Binder的引用,使得Client可以通过Binder名字获得Server中Binder实体的引用。
Binder驱动(如同路由器):负责进程之间binder通信的建立,传递,计数管理以及数据的传递交互等底层支持。
图片出自Carson_Ho文章 —— Android跨进程通信:图文详解 Binder机制 原理
7、Bundle传递对象为什么需要序列化?Serialzable和Parcelable的区别?
参考回答:因为bundle传递数据时只支持基本数据类型,所以在传递对象时需要序列化转换成可存储或可传输的本质状态(字节流)。序列化后的对象可以在网络、IPC(比如启动另一个进程的Activity、Service和Reciver)之间进行传输,也可以存储到本地。
序列化实现的两种方式:实现Serializable/Parcelable接口。不同点如图:
8、讲讲AIDL?原理是什么?如何优化多模块都使用AIDL的情况?
参考回答:AIDL(Android Interface Definition Language,Android接口定义语言):如果在一个进程中要调用另一个进程中对象的方法,可使用AIDL生成可序列化的参数,AIDL会生成一个服务端对象的代理类,通过它客户端实现间接调用服务端对象的方法。
AIDL的本质是系统提供了一套可快速实现Binder的工具。关键类和方法:
AIDL接口:继承IInterface。
Stub类:Binder的实现类,服务端通过这个类来提供服务。
Proxy类:服务器的本地代理,客户端通过这个类调用服务器的方法。
asInterface():客户端调用,将服务端的返回的Binder对象,转换成客户端所需要的AIDL接口类型对象。如果客户端和服务端位于统一进程,则直接返回Stub对象本身,否则返回系统封装后的Stub.proxy对象
asBinder():根据当前调用情况返回代理Proxy的Binder对象。
onTransact():运行服务端的Binder线程池中,当客户端发起跨进程请求时,远程请求会通过系统底层封装后交由此方法来处理。
transact():运行在客户端,当客户端发起远程请求的同时将当前线程挂起。之后调用服务端的onTransact()直到远程请求返回,当前线程才继续执行。
当有多个业务模块都需要AIDL来进行IPC,此时需要为每个模块创建特定的aidl文件,那么相应的Service就会很多。必然会出现系统资源耗费严重、应用过度重量级的问题。解决办法是建立Binder连接池,即将每个业务模块的Binder请求统一转发到一个远程Service中去执行,从而避免重复创建Service。
工作原理:每个业务模块创建自己的AIDL接口并实现此接口,然后向服务端提供自己的唯一标识和其对应的Binder对象。服务端只需要一个Service,服务器提供一个queryBinder接口,它会根据业务模块的特征来返回相应的Binder对象,不同的业务模块拿到所需的Binder对象后就可进行远程方法的调用了1、讲下View的绘制流程?
参考回答:View的工作流程主要是指measure、layout、draw这三大流程,即测量、布局和绘制,其中measure确定View的测量宽/高,layout确定View的最终宽/高和四个顶点的位置,而draw则将View绘制到屏幕上
View的绘制过程遵循如下几步:
绘制背景 background.draw(canvas)绘制自己(onDraw)绘制 children(dispatchDraw)绘制装饰(onDrawScollBars)
2、MotionEvent是什么?包含几种事件?什么条件下会产生?
参考回答:MotionEvent是手指接触屏幕后所产生的一系列事件。典型的事件类型有如下:
ACTION_DOWN:手指刚接触屏幕ACTION_MOVE:手指在屏幕上移动ACTION_UP:手指从屏幕上松开的一瞬间ACTION_CANCELL:手指保持按下操作,并从当前控件转移到外层控件时触发正常情况下,一次手指触摸屏幕的行为会触发一系列点击事件,考虑如下几种情况:
点击屏幕后松开,事件序列:DOWN→UP点击屏幕滑动一会再松开,事件序列为DOWN→MOVE→.....→MOVE→UP3、描述一下View事件传递分发机制?
参考回答:View事件分发本质就是对MotionEvent事件分发的过程。即当一个MotionEvent发生后,系统将这个点击事件传递到一个具体的View上
点击事件的传递顺序:Activity(Window)→ViewGroup→ View
事件分发过程由三个方法共同完成:
dispatchTouchEvent:用来进行事件的分发。如果事件能够传递给当前View,那么此方法一定会被调用,返回结果受当前View的onTouchEvent和下级View的dispatchTouchEvent方法的影响,表示是否消耗当前事件
onInterceptTouchEvent:在上述方法内部调用,对事件进行拦截。该方法只在ViewGroup中有,View(不包含 ViewGroup)是没有的。一旦拦截,则执行ViewGroup的onTouchEvent,在ViewGroup中处理事件,而不接着分发给View。且只调用一次,返回结果表示是否拦截当前事件
onTouchEvent:在dispatchTouchEvent方法中调用,用来处理点击事件,返回结果表示是否消耗当前事件
4、如何解决View的事件冲突 ?举个开发中遇到的例子 ?
参考回答:常见开发中事件冲突的有ScrollView与RecyclerView的滑动冲突、RecyclerView内嵌同时滑动同一方向
滑动冲突的处理规则:
对于由于外部滑动和内部滑动方向不一致导致的滑动冲突,可以根据滑动的方向判断谁来拦截事件。
对于由于外部滑动方向和内部滑动方向一致导致的滑动冲突,可以根据业务需求,规定何时让外部View拦截事件,何时由内部View拦截事件。
对于上面两种情况的嵌套,相对复杂,可同样根据需求在业务上找到突破点。
滑动冲突的实现方法:
外部拦截法:指点击事件都先经过父容器的拦截处理,如果父容器需要此事件就拦截,否则就不拦截。具体方法:需要重写父容器的onInterceptTouchEvent方法,在内部做出相应的拦截。
内部拦截法:指父容器不拦截任何事件,而将所有的事件都传递给子容器,如果子容器需要此事件就直接消耗,否则就交由父容器进行处理。具体方法:需要配合requestDisallowInterceptTouchEvent方法。
5、scrollTo()和scollBy()的区别?
参考回答:
scollBy内部调用了scrollTo,它是基于当前位置的相对滑动;而scrollTo是绝对滑动,因此如果使用相同输入参数多次调用scrollTo方法,由于View的初始位置是不变的,所以只会出现一次View滚动的效果
两者都只能对View内容的滑动,而非使View本身滑动。可以使用Scroller有过度滑动的效果
6、Scroller是怎么实现View的弹性滑动?
参考回答:
在MotionEvent.ACTION_UP事件触发时调用startScroll()方法,该方法并没有进行实际的滑动操作,而是记录滑动相关量(滑动距离、滑动时间)
接着调用invalidate/postInvalidate()方法,请求View重绘,导致View.draw方法被执行
当View重绘后会在draw方法中调用computeScroll方法,而computeScroll又会去向Scroller获取当前的scrollX和scrollY;然后通过scrollTo方法实现滑动;接着又调用postInvalidate方法来进行第二次重绘,和之前流程一样,如此反复导致View不断进行小幅度的滑动,而多次的小幅度滑动就组成了弹性滑动,直到整个滑动过程结束
7、 invalidate()和postInvalidate()的区别 ?
参考回答:invalidate()与postInvalidate()都用于刷新View,主要区别是invalidate()在主线程中调用,若在子线程中使用需要配合handler;而postInvalidate()可在子线程中直接调用。
8、SurfaceView和View的区别?
View需要在UI线程对画面进行刷新,而SurfaceView可在子线程进行页面的刷新
View适用于主动更新的情况,而SurfaceView适用于被动更新,如频繁刷新,这是因为如果使用View频繁刷新会阻塞主线程,导致界面卡顿
SurfaceView在底层已实现双缓冲机制,而View没有,因此SurfaceView更适用于需要频繁刷新、刷新时数据处理量很大的页面(如视频播放界面)
9、自定义View如何考虑机型适配 ?
合理使用warp_content,match_parent尽可能的是使用RelativeLayout针对不同的机型,使用不同的布局文件放在对应的目录下,android会自动匹配。尽量使用点9图片。使用与密度无关的像素单位dp,sp引入android的百分比布局。切图的时候切大分辨率的图,应用到布局当中。在小分辨率的手机上也会有很好的显示效果。
今天分享的面试题就到这里,还是那句话,有些东西你不仅要懂,而且要能够很好地表达出来,能够让面试官认可你的理解,例如Handler机制,这个是面试必问之题。有些晦涩的点,或许它只活在面试当中,实际工作当中你压根不会用到它,但是你要知道它是什么东西。
不管怎么样,不论是什么样的大小面试,要想不被面试官虐的不要不要的,只有刷爆面试题题做好全面的准备,当然除了这个还需要在平时把自己的基础打扎实,这样不论面试官怎么样一个知识点里往死里凿,你也能应付如流啊~
鉴于看到很多小伙伴在转发我的写的文章,我最近也总结了几套面试题,【小编在这分享总结的Java面试高频的面试题(包括了Java、MyBatis、ZooKeeper、Dubbo、Elasticsearch、Memcached、Redis、MySQL、Spring、Spring Boot、Spring Cloud、RabbitMQ、Kafka、Linux 等技术栈)都进行了整理以及打包整合,上述面试题答案都整理成文档笔记。 也还整理了一些面试资料&最新2020收集的一些大厂的面试真题(都整理成文档,小部分截图),有需要的可以 点击进入 查看领取资料。 】以下是面试资料部分截图:
点关注,不迷路!如果本文对你有帮助的话不要忘记点赞支持哦!