面试总结

周一

1Ai项目AIsdk

底层JNi层  MNN piexAI libyuv

1

MediaProjectionManager

写数据流和录屏两种,写数据流会导致卡顿、帧率下降严重、计数更不准,不建议使用, 所以目前无法换方案

获取录屏

mediaRcord    AudioRecord 

meidaPlayer    Audidotrack

MediaExtractor  M

mediaMuxer的作用是生成音频或视频文件;还可以把音频与视频混合成一个音视频文件 

https://www.jianshu.com/p/c68efedfd1c6

多态

多态就是指程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编程时并不确定,而是在程序运行期间才确定,即一个引用变量倒底会指向哪个类的实例对象,该引用变量发出的方法调用到底是哪个类中实现的方法,必须在由程序运行期间才能决定。因为在程序运行时才确定具体的类,这样,不用修改源程序代码,就可以让引用变量绑定到各种不同的类实现上,从而导致该引用调用的具体方法随之改变,即不修改程序代码就可以改变程序运行时所绑定的具体代码,让程序可以选择多个运行状态,这就是多态性。

采用多态后,易于扩展

泛型提供编译器类型安全、确保只能把争正确类型的对象放入集合中

同时在在运行时通过泛型擦除避免创建不必要的类 过度消耗

类型安全 

泛型的主要目标是提高 Java 程序的类型安全

编译时期就可以检查出因Java类型不正确导致的ClassCastException异常

符合越早出错代价越小原则

消除强制类型转换 

泛型的一个附带好处是,使用时直接得到目标类型,消除许多强制类型转换

所得即所需,这使得代码更加可读,并且减少了出错机会

在运行时我们如果需要获取泛型信息,可以定义内部类方式获取泛型参数

魔术 版本号  常量次(类对象名称 方法 参数名称)访问标志()字段描述集合和方法描述集合    属性描述集合

sdk分为三层

底层是

  1:初始化计步芯片(4.4以上通过注册step_counter 4.4一下计步通过三轴传感器 根据xy周计算出步频,通过观察者模式 回调参数相关的步数  写入数据库)

 2:初始化一个定时任务开启service后台定时上传步数采用JobScheduler,现在准备替换为workmangerjobscheadlerarlrmanger

接口层实现层

定义 网络 埋点  log.接口实现类,接入实现自己的相关工具类

获取步数类采用 动态代理 、责任链的设计模式获取步数

主要是为了优化步数不准 接入华为、vivo .魅族计步sdk 。根据不同的机型 去动态获取sdk 的步数

3统一封装jspapi 在各个端使用  获取步数、上传步数等

配合服务端和钉钉做了个自动拉取日志的脚本 输入对应参数 获取步数记录

优化

内存泄露在Android内存优化是一个比较重要的一个方面,很多时候程序中发生了内存泄露我们不一定就能注意到,所有在编码的过程要养成良好的习惯。总结下来只要做到以下这几点就能避免大多数情况的内存泄漏:

构造单例的时候尽量别用Activity的引用;静态引用时注意应用对象的置空或者少用静态引用;使用静态内部类+软引用代替非静态内部类;及时取消广播或者观察者注册;耗时任务、属性动画在Activity销毁时记得cancel;文件流、Cursor等资源及时关闭;

Activity

销毁时WebView的移除和销毁。

启动优化:displayed

1:线程池合理使用调度 

2: 子进程延时

3:Gc频繁 对象复用,减少系统调用抢占资源

4:主界面启动优化

   通过减少冗余或者嵌套布局来降低视图层次结构

用 ViewStub 替代在启动过程中不需要显示的 UI 控件

使用自定义View替代复杂的View叠加

5数据预加载(本地保存数据 加快启动速度)

1启动多线程优化

2:使用自建启动器

3使用IdleHandler

.启动阶段不启动子进程

启动阶段抑制GC

AI操房ott

首页动态化dx

将xml模板编译生成二进制格式文件,确保了基础数据类型在虚拟视图上进行计算的时候无需频繁的封箱拆箱,提高了计算效率,也减少了模板文件大小,提高了下载速度。

引入渲染管线概念,以模块化和数据驱动的方式实现组件解析、布局、渲染等整个流程,布局、测量等流程均在虚拟节点上进行,节省了直接操作视图属性的开销,另外还可以进行预渲染。

在真正渲染之前,会进行层级扁平化处理,对那些仅有占位和布局作用的Layout进行处理,只保留那些有实际渲染和交互作用的Layout视图,对不必要的层级关系进行删除或拍平,减少视图层级,降低overdraw的可能性,提升性能。

视图Diff处理,经过扁平化处理的虚拟视图树,会与当前视图所对应的虚拟视图树进行Diff操作,找出从当前视图树到新的虚拟视图树的具体指令,然后根据执行创建、删除或更新视图树。Diff操作保证每次渲染只对必要的部分进行重新渲染,相同的部分可以复用无需渲染,这样做可以极大地降低视图快速滚动时所产生的性能消耗,显著提高在容器内滑动时的帧率。

LRU缓存,尽量减少磁盘、网络IO等耗时操作。

难点

计步机型难点

yuv转bitmap

使用Java进行Bitmap转换为YUV时,一张1440 x 900的Bitmap耗时大概35 ~ 45ms左右,而使用libyuv则花费14~22 ms左右,性能提升一倍,而更暴力的来了,如果同时进行拉伸缩放和格式转换,例如1440 x 90 —> 480 x 270,可以实现5 ~ 13 ms,性能提升了3 ~ 6倍。这意味着1000 ms可以满足我们不低于25FPS的需求。

Synchronized是依赖于JVM实现的,而ReenTrantLock是JDK实现的

与synchronized相比,重入锁有着显式的操作过程,开发人员必须手动的指定何时加锁(调用lock方法),何时释放锁(调用unlock方法)。因此,重入锁对逻辑的控制性要好于synchronized。

AQS

是一个用于构建锁和同步容器的框架

ReentrantLock的基本实现可以概括为:先通过CAS尝试获取锁。如果此时已经有线程占据了锁,那就加入AQS队列并且被挂起。当锁被释放之后,排在CLH队列队首的线程会被唤醒,然后CAS再次尝试获取锁。在这个时候,如果:

非公平锁:如果同时还有另一个线程进来尝试获取,那么有可能会让这个线程抢先获取;

公平锁:如果同时还有另一个线程进来尝试获取,当它发现自己不是在队首的话,就会排到队尾,由队首的线程获取到锁。

viewModel

retainNonConfigurationInstances

getLastNonConfigurationInstance

在Android Studio Logcat中过滤关键字“Displayed”,可以看到对应的冷启动耗时日志。

http协议的特点

http特点

简单快速

无连接

无状态

request参数

User-agent浏览器名称版本

Accept 浏览器接受的类型

if-None-Mathch  配合ETAg使用

If-modified-since 

Response

响应行 响应头 响应体

ETag

last_modified

Expired:

Cache-Control

Http1.1/http1.0的区别

1缓存处理

2带宽优化 网络连接的使用

3Host头处理

4长连接

默认开启keep-live

http1.x

A:http1.x 每次需要重新连接,无疑增加延迟时间

2:明文传输

3:header 传输的内容过大,增加传输成本

4:keep-alive 使用多了会同样给服务端打来大量的性能压力

cookie和seesion的区别

1客户端和服务端

2存取的方式不同

3安全性不同

4有效期不同

5对服务器造成的压力不同

1 https

http+tls

Ssl  是一种安全传输协议  tls是ssl的升级版

ssL加密处理

https传输速度

2:TLs/ssL握手

对称加密和非对称加密(Rsa)

A:客户端发送支持的协议版本 加密算法发送给服务端

b 服务端发送确定加密的协议和版本的算法

c  验证证书 同时用公钥加密随机数

D 服务端是私钥 解密获取随机数

https在tcp和http直接加入了ssl/tls为上层保驾护航

tcp/ip

物理层/实体层

链接层(以太网协议(数据表样式) 依靠mac地址 广播(子网络传递) )

网络层 

背景:以太网采用广播方式发送数据包

Todo: 能够区分mac地址属于 同一个子网络

作用:使得我们能够区分不同的计算机是否属于同一个子网络

ip数据包

arp协议  ip地址得到mac地址

传输层

建立端口到端口的功能

应用层

规定应用程序的数据格式

dns

什么是dns 

http2.0

新的二进制格式(Binary Format),HTTP1.x的解析是基于文本。基于文本协议的格式解析存在天然缺陷,文本的表现形式有多样性,要做到健壮性考虑的场景必然很多,二进制则不同,只认0和1的组合。基于这种考虑HTTP2.0的协议解析决定采用二进制格式,实现方便且健壮。

多路复用(MultiPlexing),即连接共享,即每一个request都是是用作连接共享机制的。一个request对应一个id,这样一个连接上可以有多个request,每个连接的request可以随机的混杂在一起,接收方可以根据request的 id将request再归属到各自不同的服务端请求里面。

header压缩,如上文中所言,对前面提到过HTTP1.x的header带有大量信息,而且每次都要重复发送,HTTP2.0使用encoder来减少需要传输的header大小,通讯双方各自cache一份header fields表,既避免了重复header的传输,又减小了需要传输的大小。

服务端推送(server push),同SPDY一样,HTTP2.0也具有server push功能。

优点:

轻量级,以键值对的方式进行存储,使用方便,易于理解

采用的是xml文件形式存储在本地,程序卸载后会也会一并被清除,不会残留信息

缺点:

由于是对文件IO读取,因此在IO上的瓶颈是个大问题,因为在每次进行get和commit时都要将数据从内存写入到文件中,或从文件中读取

多线程场景下效率较低,在get操作时,会锁定SharedPreferences对象,互斥其他操作,而当put,commit时,则会锁定Editor对象,使用写入锁进行互斥,在这种情况下,效率会降低

不支持跨进程通讯

4.

由于每次都会把整个文件加载到内存中,因此,如果SharedPreferences文件过大,或者在其中的键值对是大对象的json数据则会占用大量内存,读取较慢是一方面,同时也会引发程序频繁GC,导致的界面卡顿。

建议

建议不要存储较大数据或者较多数据到SharedPreferences中

频繁修改的数据修改后统一提交,而不是修改过后马上提交

在跨进程通讯中不去使用SharedPreferences

键值对不宜过多

上帝视角看class文件

如果从纵观的角度来看 class 文件,class 文件里只有两种数据结构:无符号数和表。

无符号数:属于基本的数据类型,以 u1、u2、u4、u8 来分别代表 1 个字节、2 个字节、4 个字节和 8 个字节的无符号数,无符号数可以用来描述数字、索引引用、数量值或者字符串(UTF-8 编码)。

表:表是由多个无符号数或者其他表作为数据项构成的复合数据类型,class文件中所有的表都以“_info”结尾。其实,整个 Class 文件本质上就是一张表。

PathClassLoader 只能加载已经安装应用的 dex 或 apk 文件,DexClassLoader 则没有此限制,可以从 SD 卡上加载包含 class.dex 的 .jar 和 .apk 文件,这也是插件化和热修复的基础,在不需要安装应用的情况下,完成需要使用的 dex 的加载。

Class 对象在执行引擎中的初始化过程

ViewRootImpl中的setView方法中,除了调用IWindowSession执行跨进程添加View之外,还有一项重要的操作就是设置输入事件的处理:

ViewRootImpl的setView方法中主要完成两件事情:View渲染(requestLayout)以及接收触屏事件。

个人理解:做过 Android 开发的都知道只有 UI 线程才可以刷新 View 控件,但是事实却并非如此。在 ViewRootImpl 中对 View 进行刷新时,会检查当前线程的合法性:

图中 mThread 是被赋值为当前线程,而 ViewRootImpl 是在 UI 线程中被创建的,因此只有 UI 线程可以进行 View 刷新。但是如果我们能在非 UI 线程中创建 ViewRootImpl,并通过这个 ViewRootImpl 进行 View 的添加和绘制操作,那么后续理论上也是可以在非 UI 线程中刷新 View 控件的,只是维护成本较高,很少有人去做这件事情。

包安装

记录首先Android点击APK安装,会启动PackageInstallerActivity,然后将APK信息传给PMS,PMS会做两件事,拷贝安装包和装载代码。在拷贝安装包过程中会开启Service来copyAPK,并且会检查apk安装路径,包的状态,最终以base.apk形式存在/data/app包名下。装载代码过程中,会继续解析apk,把清单文件内容存放于PMS,然后对apk进行签名校验,再执行dex2oat优化,安装成功后,更新应用设置权限,发送广播通知桌面显示APP图标,安装失败则删除安装包和各种缓存文件

Android一直使用VSync来防止屏幕撕裂

DinamicX是目前集团内比较成熟的一套基于native的动态化方案,相比weex/RN来说,DinamicX是一套纯native的解决方案,专注于UI模板渲染,优势是高性能、高可用。虽然没有引入JS引擎,不具备执行JS脚本的能力,但也正因为这样,DinamicX并不存在诸如JS执行耗时、跨语言通信等问题,这对动态化方案也是一个很好的补充。目前集团内dinamicX多用于基础链路如下单、详情等场景,而weex则更多服务于导购域、会场等场景。

另外,与其他动态化方案不太一样的地方是DinamicX并不仅仅只是一套端上SDK,它同时还配套提供了组件平台,支持在线编辑模板、真机预览、提测、发布等一整套流程,再结合新奥创、rapid等搭建投放平台,形成一套完善的业务开发生态闭环。

https://www.cnblogs.com/Android-Alvin/p/12617606.html

    在java语言中,可作为GCRoot的对象包括以下几种:

a.java虚拟机栈(栈帧中的本地变量表)中的引用的对象。 

 b.方法区中的类静态属性引用的对象。 

c.方法区中的常量引用的对象。 

 d.本地方法栈中JNI本地方法的引用对象

亮点:

leveldb  走路和计步  app进来会打开文件fdsize>1024  系统限制

解决哈希冲突的方法一般有:开放定址法、链地址法(拉链法)、再哈希法、建立公共溢出区等方法

H5容器优化

通过WebView的addJavascriptInterface()进行对象映射

通过WebViewClient的shouldOverrideUrlLoading()方法回调拦截url

通过WebChromeClient的onJsAlert()、onJsConfirm()、onJsPrompt()方法回调拦截JS对话框alert()、confirm()、prompt()消息

https://www.jianshu.com/p/5e7075f4875f

总结:H5页面加载速度慢的原因:渲染速度慢 & 页面资源加载缓慢 导致

public emun Singleton {

   //定义一个枚举的元素,它就代表了Singleton的一个实例

   uniqueInstance;

}

新建(New)、就绪(Runnable)、运行(Running)、阻塞(Blocked)和死亡(Dead)

wait和sleep的主要区别是

调用wait方法时,线程在等待的时候会释放掉它所获得的monitor,但是调用Thread.sleep()方法时,线程在等待的时候仍然会持有monitor或者锁。另外,Java中的wait方法应在同步代码块中调用,但是sleep方法不需要

java是基于栈的架构,栈是内存上面一段连续的存储空间。

Android是基于寄存器的架构,寄存器是cpu上的一块存储空间。

二、执行的字节码文件不一样

DVM: 每个应用启动都运行一个单独的DVM,每个DVM单独占用一个Linux进程。

JVM: 只能运行一个实例,即所有的应用都运行在同一个JVM中

启动优化

冷启动:创建进程  创建application mainActivity

热启动:前后台切换

温启动:生命周期切换

启动时间测试:

onAttachWindow开始时间

feed流第一条数据显示时间getViewTreeObser().addPreDrawListener()

启动工具使用

traceview(CpuProfiler)  sysTrace(相互补充)

traceview 使用(运行时开销严重、整体变慢、可能带偏方法) 在电脑端埋点

wallclocktime  callchart  topdown查看函数的调用时间进行优化

cpu profile

sysTrace

轻量级

监控跟踪api调用、线程运行情况,生成html

直观反映cpu利用率(

cputime代码消耗cpu的时间

walltime代码执行时间

)

启动优化:

异步启动+延迟初始化

线程池复用

启动阶段启动子进程

注意contentproview启动是在application之前

启动阶段抑制Gc

谨慎sharepreferences 

提前获取页面数据

内存优化

内存抖动  内存泄露  oom

工具:Memory Profiler  leackCancay

布局优化:

Systrace 

fps监听

Chorographer.getInstance().postFrameCallback();

布局解析 

反射

LayoutInfalter  factory2  factory

AsyLayoutInfalter

卡顿优化

耗时优化:异步、延迟

布局优化:异步Infalyer

内存:降低内存占用、减少Gc 时间

bitmao内存复用

app瘦身优化

aapt  字节码  R文件 

stack pop push peek

Queue offer add,poll,remove

 PathClassLoader和DexClassLoader,大家都会说,前者只能加载内存中已经安装的apk中的dex,而后者可以加载sd卡中的apk/jar,因此DexClassLoader是热修复和插件化的基础。

 PathClassLoader只能加载已经安装应用的dex或apk文件,DexClassLoader则没有此限制,可以从SD卡上加载包含class.dex的.jar和.apk文件,这也是插件化和热修复的基础,在不需要安装应用的情况下,完成需要使用的dex的加载。

运算规则:0^0=0;0^1=1;1^0=1;1^1=0;

偏向锁:无实际竞争,且将来只有第一个申请锁的线程会使用锁。

轻量级锁:无实际竞争,多个线程交替使用锁;允许短时间的锁竞争。

重量级锁:有实际竞争,且锁竞争时间长。

android事件分发机制


异步消息

主线程消息队列中插入 SyncBarrier Message。该方法发送了一个没有 target 的 Message 到 Queue 中,在 next 方法中获取消息时,如果发现没有 target 的 Message,则在一定的时间内跳过同步消息,优先执行异步消息。这里通过调用此方法,保证 UI 绘制操作优先执行

图中注释1处就是硬件加速的特殊之处,通过updateRootDisplayList方法将View视图抽象成一个RenderNode对象,并构建View的DrawOp树。

图中 2 处通知 RenderThread 进行绘制操作,RenderThread 是一个单例线程,每个进程最多只有一个硬件渲染线程,这样就不会存在多线程并发访问冲突问题。

Android硬件加速过程中,View视图被抽象成RenderNode节点,View中的绘制操作都会被抽象成一个个DrawOp,比如View中drawLine,构建过程中就会被抽象成一个DrawLineOp,drawBitmap操作会被抽象成DrawBitmapOp。每个子View的绘制被抽象成DrawRenderNodeOp,每个DrawOp有对应的OpenGL绘制命令。

上图中 1 处就是遍历 View 递归构建 DrawOp,2 处就是根据 Canvas 将所有的 DrawOp 进行缓存操作。所有的 DrawOp 对应的 OpenGL 命令构建完成之后,就需要使用 RenderProxy 向 RenderThread 发送消息,请求 OpenGL 线程进行渲染。整个渲染过程是通过 GPU 并在不同线程绘制渲染图形,因此整个流程会更加顺畅。

常理来说,签名之后的 apk 应该是可以正常安装使用了,但是实际打包过程还会多一步 apk 优化操作。就是使用工具 zipalign 对 apk 中的未压缩资源(图片、视频等)进行对齐操作,让资源按照 4 字节的边界进行对齐。这种思想同 Java 对象内存布局中的对齐空间非常类似,主要是为了加快资源的访问速度。如果每个资源的开始位置都是上一个资源之后的 4n 字节,那么访问下一个资源就不用遍历,直接跳到 4n 字节处判断是不是一个新的资源即可。

leackCanary

内存泄漏的检测时机  idhandler

特殊机型适配

因为有些特殊机型的系统本身就存在一些内存泄漏的情况,导致 Activity 不被回收,所以在检测内存泄漏时,需要将这些情况排除在外。在 LeakCanary 的初始化方法 install 中,通过 excludedRefs 方法指定了一系列需要忽略的场景。

Android 6.x

新增运行时权限概念

移除对Apache HTTP client的支持,建议使用HttpURLConnection。如果还是想用Apache HTTP client

Android 7.x

加入原生分屏多任务功能,多任务快速切换

引入全新的JIT编译器,使得App安装速度快了75%,编译代码的规模减少了50%

安全:更安全的加密模式,可以对单独的文件进行加密,android系统启动加密

Android O(安卓8.0

画中画

后台进程限制

android9.0

1、刘海屏适配

Android10.0

AndroidQ引入了大量更改和限制以增强对用户隐私的保护。

https://blog.csdn.net/xxx_19942/article/details/106208604

栈帧数据结构

方法区(Method Area)与 Java 堆一样,是各个线程共享的内存区域,它用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据

i++ ++i 的区别:

i++:从局部变量表取出 i 并压入操作栈(load memory),然后对局部变量表中的 i 自增 1(add&store memory),将操作栈栈顶值取出使用,如此线程从操作栈读到的是自增之前的值。

++i:先对局部变量表的 i 自增 1(load memory&add&store memory),然后取出并压入操作栈(load memory),再将操作栈栈顶值取出使用,线程从操作栈读到的是自增之后的值。

GcRoot的种类

1.虚拟机栈:栈帧中的本地变量表引用的对象

2.native方法引用的对象

3.方法区中的静态变量和常量引用的对象

线程的几种状态

新建  就绪  运行 阻塞 死亡

双亲委派机制

findclass 

Loadclass

在一个Activity执行完onDestroy()之后,将它放入WeakReference中,然后将这个WeakReference类型的Activity对象与ReferenceQueque关联。这时再从ReferenceQueque中查看是否有没有该对象,如果没有,执行gc,再次查看,还是没有的话则判断发生内存泄露了。最后用HAHA这个开源库去分析dump之后的heap内存。

启动页那个白屏优化

设置闪屏图片主题

为了更顺滑无缝衔接我们的闪屏页,可以在启动 Activity 的 Theme中设置闪屏页图片,这样启动窗口的图片就会是闪屏页图片,而不是白屏。

业务优化

线程池优化

布局优化

gc优化

启动框架优化

bitmap引用本身所在的位置(栈),引用指向的对象所在的位置(堆),对象中持有的像素数据所在的位置,像素数据在不同系统版本所在的位置略有不同,导致bitmap所占用的内存的释放方式也有所不同

一、何为加载因子?

加载因子是表示Hsah表中元素的填满的程度.若:加载因子越大,填满的元素越多,好处是,空间利用率高了,但:冲突的机会加大了.反之,加载因子越小,填满的元素越少,好处是:冲突的机会减小了,但:空间浪费多了.

冲突的机会越大,则查找的成本越高.反之,查找的成本越小.因而,查找时间就越小.

因此,必须在 "冲突的机会"与"空间利用率"之间寻找一种平衡与折衷. 这种平衡与折衷本质上是数据结构中有名的"时-空"矛盾的平衡与折衷

java1.8优化

因此,我们在扩充HashMap的时候,不需要像JDK1.7的实现那样重新计算hash,

**只需要看原来的hash值在扩容后新增的那一位是1还是0,如果是0的话索引没变,是1的话索引变成“原索引+oldCap”

亮点:

自己搭了一个计步

屏幕适配

你可能感兴趣的:(面试总结)