Android知识
1.PathClassLoader和DexClassLoader的区别:
PathClassLoader的optimizedDirectory为null,所以只能去data/dalvik-cache目录加载dex,apk安装的时候,会把优化后的dex放在data/dalvik-cache的目录,所以PathClassLoader只能加载已经安装的apk
2.Acrivity启动流程
Activity生命周期onAttach-onCreate-onStart-onResume在一个主线程的消息处理中执行
3.插件化方案
插件Activity启动方案
1.hook Instrumentation重写startActivity方法和newActivity方法
2.hook AMS重写startActivity,替换H类
加载插件类的方案:
1.每个插件创建自己的ClassLoader
2.将插件的dex数组合并到宿主APP的dex数组中
3.自定义一个ClassLoader替换掉整个APP的ClassLoader
加载插件中资源的方案:
1.每个插件创建自己的AssertManager和Resource
2.将插件的资源路径添加到宿主App的AssertManager中,需要解决资源id冲突问题,可以修改aapt
资源id:packageId+TypeId+EntryId
packageId默认等于0x7f,不同的插件可以替换成不同的packageId比如0x11
4.android图片适配原则:
首先会在对应的目录中寻找,如果没有找到,接着在分辨率更高的目录查找,如果还没找到,在drawable-nodpi目录中查找,还没找到,去分辨率更低的目录查找,如果一个xxhdpi屏幕加载一个hdpi目录的图片。图片会被放大,反之则缩小,drawable-nodpi目录的图片不会被放大和缩小
5.AsyncTask:
默认会串行执行,可以手动改成并行执行,AsyncTask中线程池是static变量,所以一个进程中所有的AsyncTask都使用共同的线程池,减少资源开销
https://www.cnblogs.com/absfree/p/5357678.html
AsyncTask:
mWorker:WorkerRunnale类型实现Callable接口,call方法中调用doInBackground方法
mFuture:FutureTask类型,传入mWorker
SerialExecutor:实现Executor接口,调度任务,使之线性执行
FutureTask:
实现Runnable和Future接口,内部组合一个Callable用于执行任务
get方法回挂起调用线程,当任务执行完成时,唤醒调用线程,
内部在进行多线程操作时进行CAS(CompareAndSwap)判断
6.性能优化:
1.卡顿优化
- 减少view树层级,工具:Hierarchy View,merge标签
- 使用ViewStub,提高显示速度
- 避免过度绘制,工具GPU过度绘制
- 避免在主线程中进行耗时操作
- 布局复用,比如ListView
- 尽量使用LinearLayout替代RelativeLayout,减少测量次数,RelativeLayout会进行两次测量, FrameLayout如果为wrap_content,则会对match_parent的子View进行两次测量
- 使用工具GPU渲染模式,查看渲染信息
- 避免频繁大量的创建对象,减少GC频率
2.内存优化
- 合理的使用软引用和弱引用,避免内存泄露
- 合理的使用对象池,视图复用,Bitmap对象复用,减少内存开销
- 使用最优的数据类型,比如SparseArray代替HashMap
- Bitmap加载时使用simpleSize进行缩放后在加载
3.稳定性优化
- 开发期间做好CodeReview
- 使用静态代码扫描工具,lint
- Crash监控与上报
4.网络优化:
- 数据压缩GZip
- 使用http缓存
- http1.0,1.1,2.0
- 网络状态:4G和Wifi下日志上报的策略发生改变
6.1:APP卡顿检测方案:
1.给主线程Handler添加日志输出类,检测dispatchMessage的执行时间
2.给Choreographer添加回调,如果两次回调的时间大于16ms,说明卡顿
6.2:DNS优化
传统DNS系统的缺点:
1.查询速度慢:显示本地DNS服务器,然后是根域名服务器,然后是顶级域名服务器
2.容易发生DNS劫持
使用HttpDns:
两种方案:
- 在网络请求前,通过HttpDns查询ip地址,然后通过ip直连请求网络,并且将http header中的host设为原来的域名
缺点:
1.https证书验证,https证书验证是需要验证域名,可以通过hook相关方法,将ip替换回域名
2.cookie或者keep-alive也需要适配 - 重新定义网络的dns部分,替换为使用HttpDns查询ip,比如OkHttp就对外暴露了替换dns部分的接口
https://www.jianshu.com/p/b0c154215b48
7.Gradle:
Gradle生命周期
1.初始化:初始化阶段确定有哪些项目参与构建,并且为这些项目创建Project对象
2.配置:配置阶段执行每个项目的build文件
3.执行:执行构建task
Gradle构建的过程中可以添加hook函数,监听构建过程
gradlewrapper:可以保证在没有安装gradle或者gradle版本不兼容的机器上,快速下载安装gradle
classpath:使用在buildscript,用于表示构建时gradle自身所需要的资源,不会编译到最终apk中
implementation:表示打包过程中,我们的项目本身所要依赖的资源,会被打进最终的apk中
extention
Task
NamedDomainObjectContainer
https://blog.csdn.net/yanbober/article/details/65635040
https://blog.csdn.net/qq_28282317/article/details/79917547
8.SurfaceView与TextureView的区别
SurfaceView:
1.在自线程刷新View
2.看似的view树中,其实在WMS中作为一个独立的window,用有独立的Surface,所以不能进行平移旋转等操作
TextureView:
1.在子线程中刷新View
2.只能在开启硬件加速的窗口中使用
3.作为一个普通的View添加到View树中,可以平移旋转
SurfaceTexture:
1.可以将数据流转换成OpenGl使用的外部纹理,供TextureView或GLSurfaceView渲染
8.1:TextureView的使用场景:
1.小屏切大屏,或者跨页面的无缝衔接播放
https://www.jianshu.com/p/4e2916889f27
9.Handler
https://blog.csdn.net/wsq_tomato/article/details/80301851
发送消息的时候,会将Message的when属性设置为消息执行的时间戳,比如发送delay消息时,when等于当前时间戳加上delay,Message在加入消息队列的时候,会根据when属性,从小到大排序,小的先执行
9.1.Handler为什么不会阻塞主线程:
android应用程序在启动的时候,会在main方法中创建ActivityThread,并且为主线程创建Looper,进入消息循环,这样才不会导致主线程因为代码执行完毕而退出,activity的生命周期都是建立在主线程的消息循环上的,ApplicationThread在binder线程收到AMS的消息后,通过ActivityThread的H类给主线程的消息循环发送消息,执行相应的生命周期
当消息队列没有可执行消息时,线程会进入休眠状态,释放CPU资源,当有消息可执行时唤醒线程,阻塞时不会消耗大量CPU资源
https://www.zhihu.com/question/34652589
10.事件分发:
mFirstTouchTarget:保存消费该事件的子View
1.只有满足down事件或者mFirstTouchTarget !=null,才会调用onInterceptTouchEvent
2.如果onInterceptTouchEvent返回true,并且mFirstTouchTarget不为null,则将事件改为cancle事件传递给mFirstTouchTarget,并且将mFirstTouchTarget=null,则后面的事件不会在传递给mFirstTouchTarget,并且不会在调用onInterceptTouchEvent
https://www.jianshu.com/p/b85d2d85ff9d
11.RecyclerView分析:
RecyclerView:
1.measure过程:
measure过程分为3步,第一步dispatchLayout1:记录当前界面显示的View的上下左右四个位置
第二步dispatchLayout2:调用LayoutManager的onLayoutChildren,首先寻找锚点,然后一次向上和向下填充View,并且进行子View的measure和layout,在填充View的前后都会进行一次View回收
第三步dispatchLayout3:保存重新布局后的View的上下左右四个位置,然后执行动画,根据view的布局前后的坐标变化执行动画
2.滑动过程:
通过调用子view的offsetTopAndBottom实现View移动,移动之前通过fill方法填充新View和回收移出的view
通过scroller实现fling
3.view复用:
view复用分为4级:scrapped,cache,extensionCache,viewpool
scrapped:重新的layout时,recyclerView会先把界面上的view回收到scrappedview中,重新布局时复用,scrapped中的viewolder不需要重新绑定数据
cache:recyclerView在上下滑动的时候,会把滚出去的viewhodler添加到cache中,默认只保存两个,按position保存的,当再次进入的时候复用,不需要重新绑定数据
viewpool:cache中保存不下的view会回收到viewpool中,不同的Recyclerview可以使用同一个viewpool。复用时需要重新绑定数据
https://juejin.im/entry/586a12c5128fe10057037fba
12.EventBus
1.EventBus在进行注册的时候,会通过反射找到订阅事件的方法,并且保存在两个Map中,在收到消息时,直接在Map中查找即可,分别是1.subscriptionsBuyEventType,通过EventType查找订阅者和方法,2.typeBySubscriber,通过订阅着查找订阅事件
https://www.jianshu.com/p/83e44261e095
13.Activity异常时生命周期:
1.在onCreate中调用finish方法,会直接调用onDestory方法
2.系统配置发生变化时,比如横竖屏切换,会导致activity销毁重建,销毁时onStop之前回调onSaveInstanceState,重建时onStart之后回调onRestoreInstanceState
3.设置configChange属性,可以在系统配置发生变化时,禁止activity重建
4.内存不足时会导致优先级低的activity被杀死,并且回调onSaveInstanceState方法保存状态
14.Fragment:
1.Activity销毁重建的时候,FragmentManager自动重建之前的Fragment,所以在onCreate方法中创建Fragment之前应该先判断一下FragmentManager是否已经创建了该Fragment
2.Activity给Fragment传参的时候,应该使用setArgument方法,因为Activity在销毁的时候,会保存Fragment的状态以及对应的Argument,并且在重建的时候使用
3.操作Fragment的几个常见方法
1.add:将Fragment添加到容器,执行onAttach -> onResume
2.remove:add的逆过程中,onResume->onDetach,移除时如果加入退回栈,则只会销毁视图,即只回调到onDestoryView
3.replace:移除之前的Fragment,重新添加新的
4.detach:只是销毁视图,onPause,onStop,onDestoryView
5.attach:onCreateView,onActivityCreated,onStart,onResume
6.hiden:将fragment隐藏,不执行生命周期,回调onHiddenChange
7.show:不执行生命周期
https://www.jianshu.com/p/3d27ddc952fe
FragmentManager中mAdded 和 mActive的区别
mActive保存活着的fragment,添加fragment时保存到mActive中,调用onDetach后从mActive中移除
mAdded表示添加到FragmentManager中的fragment,添加fragment时添加到mAdded中,调用remove或者detach的时候,从mAdded中移除
14.1 懒加载
需要注意的点:
1.setUserVisibleHint为true
2.Fragment已经初始化完成
3.第一页Fragment调用setUserVisibleHint的时候,Fragment还没有初始化完成所以需要在onActivityCreate方法中在进行一次加载请求
14.2 fragment生命周期源码分析
1.在onCreate中添加fragment的生命周期
2.在onClick中添加fragment的生命周期
3.在ViewPager中的生命周期
https://www.jianshu.com/p/f2fcc670afd6
14.3 Fragment状态保存和恢复
http://www.androidchina.net/6317.html
15.FragmentPagerAdapter和FragmentStatePagerAdapter区别:
1.两个都会提前创建limit个Fragment
2.第一个Adapter在Fragment滑入的时候,会判断Fragment是否已经添加,如果没有则创建并且执行add,否则只执行attach,如果fragment移除limit需要销毁时,只执行detach销毁视图,Fragment实例并没有被销毁
3.第二个Adapter在划入时,先从缓存拿,如果有,直接返回,否则创建实例,并且执行add方法,在移除时,调用remove方法,清理缓存保存状态,状态在下次重建时使用
https://www.jianshu.com/p/6e7f894014b8
16.RelativeLayout与LinearLayout:
1.RelativeLayout会分别在水平方向和垂直方向各测量一次,LinearLayout在没有设置weight的时候进行一次测量,设置weight的时候,进行两次测量
2.优先使用LinearLayout,如果LinearLayout可能增加view层级或者需要使用weight,则使用RelativeLayout
https://www.jianshu.com/p/b9bd08ffe921
17.LeakCanary原理:
通过ActivityLifeCycleCallback监听activity生命周期,activity调用onDestory后创建一个activity的weak引用,并且关联一个引用队列,然后再子线程中判断引用队列是否有该weak引用,如果没有,则触发一个GC,在次判断引用队列中是否有该weak引用,如果有,则可能发生内存泄露,dump内存快照分析内存文件
18.属性动画原理:
属性动画开始的时候,会将自己作为callback添加到单利AnimationHandler中的一个List中,AnimationHandler有一个Choreographer.FrameCallBack的对象,choreographer收到垂直信号后,会回调这个对象的doframe方法,在这个方法中AnimationHandler会回调会有属性动画callback,属性动画会根据interpolator计算因子,并且根据差值器Evaluator计算出当前的变化值,进行动画
https://www.jianshu.com/p/d9deeffc1498
18.1View动画原理:
https://www.jianshu.com/p/48317612c164
19.加载Bitmap:
1.计算一张图片的大小:width * height * 4
2.设置了inSampleSize = 2,一张图片的大小:width / 2 * height / 2 * 4,所以在加载一张大图的时候,可以根据UI宽高,计算好inSampleSize
3.通过native加载一个Bitmap的时候,会传入图片坐在目录的density和屏幕密度targetDensity,native会计算缩放比例scale = targetDensity / density,然后加载图片。所以图片会被放大和缩小
4.实际图片所占内存大小:width * scale /sampleSize * height * scale / samplesize * 4
https://blog.csdn.net/jzman/article/details/88047730
20.Android多进程的优点:
1.分担主进程的内存压力,可以将一些比较耗费内存的模块放在一个独立的进程中
2.主进程和守护进程可以相互监视,有一方被杀重新启动它
缺点:
1.静态变量和单例全部失效:因为不同进程有独立的地址空间
2.线程同步机制完全失效
3.sp的可靠性下降:多进程读写文件,可能会出错
4.Application会多次创建
进程与线程的区别:
进程有自己独立的地址空间,一个进程崩溃后,不会对其进程产生影响,线程只是一个进程中的不同执行路径,线程有自己的堆栈和局部变量,但线程没有独立的地址空间,一个线程死掉,会导致整个进程死掉
https://blog.csdn.net/csdn_aiyang/article/details/69734557
21.ART与Dalvik区别:
dalvik是在每次运行时将dex文件转换成机器码,ART是在安装的时候将dex转换成机器码
ART的优点:
1.应用启动更快,运行更快,体验更流畅
2.更长电池续航能力
3.ART的性能高于dalvik
缺点:
1.安装速度慢
2.字节码转换成机器码后,占用的存储空间更大
https://www.jianshu.com/p/58f817d176b7
22.Serializable与Parcelable:
- serialVersionUID:只有serialVersionUID一致的时候,才能序列化成功
2.静态成员变量属于类,不属于对象,所以不能被序列化
3.transient修饰的变量,不能被序列化
4.数据持久化选择Serializable,Intent传递优先使用Parcelable,Parcelable性能优于Serializable
https://www.jianshu.com/p/2ed41bb7aa3a
23.AIDL:
AIDL用到的几个类:
1.IInterface:返回一个IBinder对象,表示可以进行binder通信
2.自己定义的接口类,继承自IInterface
3.Stub:继承自Binder,表示是一个Binder对象,可以进行跨进程调用,实现了自定义接口
4.Proxy:实现了自定义接口,Stub类的代理类
客户端通过ServiceConnection返回一个Bindler对象,因为不在同一个进程,所以客户端不能直接使用这个Bindler对象,通过这个Binder对象创建一个Proxy对象,可以通过使用Proxy对象,调用service服务
https://www.kancloud.cn/alex_wsc/android_plugin/480780
23.1:AIDL需要注意的问题:
1.AIDL的调用流程:
2.Binder死亡监听:DeathRecipient
3.Binder线程池:默认最多15个线程,可以修改
4.Client如果在主线程调用可能会ANR
5.权限验证:可以在onBinder验证,也可以在onTransact方法验证,在onTransact方法中可以进行包名验证
23.2:AIDL与Messager的区别:
1.AIDL支持面向对象调用,
2.AIDL支持高并发,Messager最终是将消息发给handler,线性处理
3.Messager使用简单
https://juejin.im/entry/589537b82f301e006904eb3e
23.3:Binder原理
https://blog.csdn.net/universus/article/details/6211589
24.Fresco分析:
可以将Fresco划分为3部分:
1.DraweeView:DraweeHierarchy,FadeDrawable,Drawable数组
2.Controller
3.ImagePipeline:ProduceSquence,MemoryCacheProduce,DecodeProduce,EncodeCacheProduce,DiskProduce,NetProduce还有分别对应的Consume
https://juejin.im/post/5a7568825188257a7a2d9ddb
25.OkHttp:
OkHttp通过一些拦截器对整个Http请求进行了封装,每个拦截器的处理过程分为:1.网络请求前处理,2.通过下层拦截器进行数据处理,3.网络请求后处理
主要的拦截器有:
RetryAndFollowUpInterceptor:重试和重定向拦截器,主要是在网络请求后,根据返回结果判断是否需要重新请求
BridgeInterceptor:1.在网络请求前往请求Header里面添加参数,比如ContentLength,ContentType,2.网络请求后,解析响应header里面的参数
CacheInterceptor:处理Http缓存逻辑,包括强制缓存max_age和对比缓存
ConnectInterceptor:进行socket链接
CallServerInterceptor:进行数据交换
为什么需要3个随机数
计算机中都是伪随机数,一个容易被猜出来,三个随机性更高一些
SPDY:
1.多路复用
2.请求优先级
3.header压缩
4.server推送
Http2.0:
Http2.0可以看成是SPDY的升级版
1.多路复用
2.header压缩
3.请求优先级
4.server推送
线程调度
Dispathcer:
如何连接socket
StreamAllocation,RealConnection,ConnectionPool,ConnectionIntercept,HttpCodec
如何缓存
CacheIntercept,CacheStrategy,CacheControl,DiskLruCache
https://www.jianshu.com/p/116ebf3034d9
25.1 http2.0与Okhttp
https://juejin.im/post/5c789dbce51d451ecc2028e7
26.Cookie:
Http是一种面向连接的无状态协议,也就是说,第一次请求和第二次请求之间没有任何联系,但是通常情况下,客户端在登陆完成后,后面的每次请求server应该知道客户端已经登陆,所以可以使用cookie来记录一些状态,登陆的时候,server响应消息的header里面添加set_cookie,客户端保存该cookie,下次请求的时候带上cookie,server便认为客户端已经登陆,可以使用CookieManager保存和获取cookie
27.加密:
非对称加密:公钥加密私钥解密,可以用于交换数据,私钥加密公钥解密,可以用于数字签名
CA机构:服务器可以将自己公钥在CA机构认证,CA机构生成一个包含该服务器公钥的签名证书,并且使用CA机构的私钥加密,客户端会保存一些CA机构公钥和信息,客户端收到签名证书后,通过CA的公钥解密,然后获取服务器的公钥
对称加密算法:DES,AES
非对称加密算法:RSA,DSA,ECC
签名算法:MD5,SHA1
28.Https:
Https = http + ssl,ssl位于应用层个传输层之间安全套接字层,提供了身份认证,数据加密和数据完整性校验,ssl的握手过程:
1.客户端向服务器say hello,并且发送自己所支持的加密算法,一个随机数
2.服务器向客户端say hello,从客户端支持加密算法中选择一个,一个随机数,服务器证书
3.客户端校验证书,获取服务器公钥,生成一个随机数,并且用公钥加密发给服务器,使用秘药生成算法和上面3个随机数,生成堆成加密的秘药
4.服务器使用私钥解密,同样使用3个随机数生成对称加密的密钥,并且告诉客户端握手完成
https抓包:主要手机安装并且信任抓包工具的证据,就可以抓https
https://juejin.im/post/5aeee624f265da0b8e7f4cdb
28.1:Https抓包和反抓包
CA证书的内容:
1.申请者公钥
2.申请者信息
3.有效期
4.CA机构签名
客户端在拿到证书以后,通过内置CA公钥解密签名,验证证书
https抓包:
charles作为中间人将自己证书替换为服务器的证书,发送给客户端,只要客户端信任这个证书,就可以通过验证,后续的通信都会被charles拦截
https反抓包:
1.客户端内置服务器证书,如果客户端判断服务器返回的证书和内置的不一样,则拒绝通信
缺点:证书到期后,需要将新的证书重新内置到APP中
2.客户端内置服务器的公钥:如果返回的证书中的公钥和内置的公钥不一样,则拒绝通信,只要服务器不更改私钥,公钥则一直有用
https://juejin.im/post/5c9cbf1df265da60f6731f0a
29.TCP:
三次握手是为了保证双方都可以发送数据和接受数据
四次挥手的状态变化,TIME_WAIT的目的
tcp是面向连接的,可靠的,基于数据流的传输层协议
udp是无连接的,不可靠的传输层协议
https://juejin.im/post/5ba895a06fb9a05ce95c5dac
30.MVC MVP MVVM:
结合自己项目,说说自己对代码架构划分的理解
https://www.cnblogs.com/wytiger/p/5305087.html
31.DataBinding原理:
1.DataBinding如何避免多次findViewById:
每次findViewById都会对View进行递归调用,找到对应的View,DataBinding在创建的时候,通过一次递归调用,将View保存在一个数组中,使用的时候,直接从数组中拿,避免了多次递归调用
2.DataBinding通过观察者模式,实现数据发生变化时更新View
https://blog.csdn.net/u012933743/article/details/78207447
32.APK签名:
Android APK签名是一种自签名,不需要CA认证,开发者使用私钥加密,应用程序安装时,使用公钥解密,并且对比摘要,只有校验通过,才能安装,因为不需要CA认证,所以其他人可以对APK进行重新签名
https://blog.csdn.net/itachi85/article/details/6564053
33.设计一个图片三级缓存框架:
https://juejin.im/post/5bca698751882576676f606a#heading-13
33.1: 自己实现一个图片加载框架:
异步图片加载框架
支持内存和磁盘缓存、支持按指定尺寸加载图片、支持从网络,文件,res目录加载图片、支持占位图和加载失败图
https://github.com/greekgoddess/BitmapLoader
Glide:
1.生命周期
2.内存缓存
3.磁盘缓存
4.BitmapPool
33.2:ImageView的ScaleType:
matrix
fit_xy
fit_start
fit_end
fit_center
center
center_crop
center_inside
https://www.jianshu.com/p/64790fce98e2
33.2: Glide源码分析:
https://www.cnblogs.com/guanmanman/p/7040942.html
34.view的measure,layout,draw过程:
1.measure:首先调用decorView的measure->onMeasure,在onMeasure中便利子View,调用子View的measure方法,decoreView的MeasureSpec是window的宽高和MATCH_PARENT,
2.layout:首先调用decoreView的layout->onLayout,在onLayout中便利子View,调用子View的layout方法,FrameLayout的onLayout方法会根据子view的gravity将子View放在一个合适的位置
3.draw:decorView的draw,在draw方法中分别调用drawBackground(如果全透明则不会调用),onDraw(如果全透明的则不会调用),dispatchDraw(绘制子view),drawForeground,
https://www.jianshu.com/p/48601578c9a8
34.1: view的工作流程measure,layout,onDraw
https://blog.csdn.net/qian520ao/article/details/78657084#commentBox
34.1.1:MeasureSpec:
1.若子View是具体的尺寸,则mode为EXACTLY,size为childSize
2.若子View是match_parent,则mode同父mode,size为parentSize
3.若子View是wrap_content,则mode为AS_MOST,size为parentSize,表示不可超过父size
34.2: android屏幕的刷新机制
https://www.jianshu.com/p/0d00cb85fdf3
34.2.1:什么是硬件加速
34.3: 自己实现一个ListView:
自定义View实现系统ListView功能
支持View复用,支持notifyDataSetChanged,支持滑动手势结束后继续滚动
https://github.com/greekgoddess/CustomListView
35.混淆
- 代码混淆的好处:
1.类名和包名都被重定义为无意义的命名,提高安全性
2.删除无用类方法和变量
3.优化字节码 - 资源压缩:
1.删除无用资源,减少包大小
https://juejin.im/post/5d1717996fb9a07eeb13bc95
36.android打包流程:
1.使用aapt工具打包res资源,生成R文件
2.AIDL转化为java文件
3.编译java代码成class文件
4.使用dex命令,将class文件转换成dex文件
5.使用apkBuilder工具将资源还有dex文件打包成apk包
6.对apk包进行签名
7.通过zipalign对apk包进行对齐处理
36.1 资源打包的过程:
1.将文本类型的XML文件编译为2进制格式,并且有一个字符串常量池,保存xml标签,属性名,属性值等,减少体积大小
2.优化压缩Bitmap类型的资源
3.生成R文件
4.生成resources.arsc文件,该文件保存了资源ID和资源名称已经路径的表格
5.res/raw或者asset目录下的资源直接打包
http://zuoquanxiong.com/Android
36.2 class转换成dex:
class文件结构:
1.魔数
2.版本号
3.常量池
4.类信息(父类,接口)
5.字段信息
6.方法信息
Dex文件结构:
1.Header
2.string信息
3.proto方法原型信息
4.field_ids字段信息
5.method_ids方法信息
6.class_defs类信息
7.data数据区
dex相比class的优势:
1.体积更小,去掉了不同class之间冗余的信息
2.加载更快,避免了每次加载类都进行一次io操作,因为一个Dex文件包含了很多class
dex文件结构
class文件结构
37.onAttachedToWindow和onDetachedFromWindow
Activity在启动时,当DecoreView添加到WindowManager时会调用onAttachedToWindow,当Activity销毁时,decoreView从windowManager移除时,会回调onDetachedFromWindow,子View从父View移除时,也会回调onDetachedFromWindow
https://www.jianshu.com/p/e7b6fa788ae6
38.自己实现一个网络加载框架
网络请求框架
实现多线程异步网络请求、支持Http缓存、支持请求重定向、支持失败重试、支持GET,POST等常见Http请求、支持用户自定义返回数据类型
https://github.com/greekgoddess/NetworkFrame
39.自己实现一个资源下载器
支持多任务,多线程下载资源
https://github.com/greekgoddess/ResourceDownloder
40.线上OOM分析:
1.尽可能多的统计发生OOM时,用户操作的上下文,包括手机型号,内存大小,activity栈
2.分析用户操作上下文,寻找稳定的复现路径
3.dump内存文件,使用MAT分析内存文件
40.1.anr分析:
1.分析trace文件,trace文件会保存发生anr时的方法调用栈,进而找到发生anr的代码
2.使用BlockCanary检测主线程耗时
41:Android新版本适配
6.0:动态权限申请
7.0:
-
系统广播删除:网络状态变更广播,拍照广播,录像广播,只有通过动态注册才能接收广播
-
应用间共享文件限制:FileProvide
8.0:
- 所有通知需要提供通知渠道
- 取消隐式广播
9.0:禁止http请求网络
https://blog.csdn.net/weixin_38261570/article/details/81046352
42:WebView总结:
1.Android调Js:
- loadUrl:
- evaluateJavascript:4.4以上可用,效率高
2.Js调Android:
- 通过addjavascriptInterface进行对象映射
存在漏洞:
4.2之前js可以中java对象上的任意方法
4.2之后,google做了限制,只能执行@javascriptInterface注释的方法
解决办法:
4.2之前使用prompt,4.2之后可以使用addjavascriptInterface - shouldOverrideUrlLoading拦截url,scheme协议
- 拦截alert,confirm,prompt消息
3.WebView漏洞:
- addjavascriptInterface方法
- 密码明文存储:询问用户是否保存密码弹窗
解决办法: 关闭密码保存 - file协议访问应用程序私有目录
解决办法: 不用要访问文件系统的时候,禁止file协议,需要的时候禁止file协议加载js
4.WebView缓存和预加载:
缓存:
- 浏览器缓存:也就是http协议缓存
- AppCache:
- Dom Storage:key-value,类似于SP,5M存储空间
- DataBase缓存:
- IndexedBase:也是Key-Value存储,是一种NoSQL数据库,可以存储复杂数据结构,4.4以上支持,取代DataBase
预加载:
- 预加载WebView:可以在Application提前加载WebView,提高显示速度
- 预加载H5:可以通过WebView提前加载H5,需要时直接addView即可
- 自身构建缓存:通过重写WebViewClient的shouldInterceptRequest拦截H5的资源请求,进行缓存和读取
https://blog.csdn.net/carson_ho/article/details/71402764
Java知识:
1.重写equals时需要重新hashCode方法
2.SparseArray,ArrayMap
SparseArray:
时间换空间
优点:使用int代替Integer,内存占用少,
缺点:
1.使用二分查找法找到Key的index,相比于HashMap查找速度慢,不适合大量数据
2.添加新元素时,需要移动数组元素
扩容:2倍扩容,扩容时需要移动数组
HashMap:
扩容时需要对所有元素重新hash
位运算代替取模,提高性能,容量必须为2的次方
hash链表大于8个时,使用红黑树
ArrayMap:
保存两个数组,一个是hash数组,一个是key,value数组,查找时,对key的hash值进行二分查找,找到在hash数组中的index,然后对应key,value数组中取出值
扩容:为缓存容量为4和8的数组,优先使用缓存数组
hash冲突时,从找到的index开始,分别向两头遍历,找到正确的index
https://blog.csdn.net/zxt0601/article/details/78333328
3. CopyOnWriteArrayList:
1.对数组进行写操作时,先加锁然后对原始数组进行copy,并且对新数组进行修改操作后,将新数组设置为List的属性,读操作不进行加锁
2.存在弱一致性问题,也就是说,对list进行读操作时,如果其他线程进行了写操作,读出来可能仍然是旧的数据,
3.适用于多读少写的情况
4.多线程同步
volatile:
1.可见性
2.禁止指令重排续
3.volatile修饰引用类型:只能保证引用地址的可见性,不能保证引用对象元素的可见性
synchronized:
1.可见性
2.原子性
3.有序性:因为一次只有一个线程访问,所以可以保证有序性
为什么多线程操作可能出问题:
每个线程在执行的时候都有自己的工作内存,线程在使用一个变量的时候,会先把这个变量从主存复制到工作内存,使用完后,再从工作内存刷新主存,但是从工作内存刷新主存的时间是不可预期的,所以,有可能一个线程修改了变量,但是还没有刷新主存,另一个线程去读变量,就会读到旧的数据
什么是工作内存:
工作内存可以理解为CPU的高速缓存,因为CPU的运算速度远远高于内存的读写,使用高速缓存可以提高CPU效率
什么是可见性:
一个线程对变量的修改可以立刻刷新主存,并且通知其他线程缓存失效
synchronized如何保证可见性:
jvm规定
1.一个线程在对共享变量lock之前必须清空工作内存中的共享变量,从而在使用共享变量的时候,需要重新从主存读取
2.一个线程在对共享变量进行unlock的时候,必须刷新最新值到共享变量
volatile的使用场景:
1.单例模式
2.一个线程写,多个线程读
https://juejin.im/post/5b35af3151882574aa5f69c5
5.类加载的过程:
加载,验证,准备,解析,初始化
1.加载:加载二进制流到内存方法区,并且生成Class对象
2.验证:
- 文件格式验证:是否已魔数开头,主次版本号是否在当前虚拟机范围内
- 元数据验证:这个类的父类是否允许被继承(final类不允许被继承),这个类是否实现了父类或者接口中的所有抽象方法,类中是否出现不合理的重载
- 字节码验证:保证语义的合理性,比如类型转换是否合法
- 符号引用验证:校验通过符号引用能否找到对应的类,符号引用所指向的信息是否有访问权限(public, private)
3.准备:为static变量分配内存,并且设置默认值,在方法区中分配内存,常量的初始值就是代码中设置的值
4.解析:将符号引用转换成直接引用
5.初始化:调用类构造器,执行static块,为static变量设置代码中的默认值,静态代码块按顺序执行
https://www.cnblogs.com/linghu-java/p/8551360.html
设计模式:
单例模式:Choreographer
适配器模式:ListView
观察者模式:Adapter的notifySetDataChange
享元模式:MessagePool
Builder模式:AlertDialog
代理模式:AIDL
工厂模式:
原型模式:clone
迭代器模式
组合模式:ViewGroup和子View
装饰器模式:ContextWrapper
模版方法模式:Activity生命周期
备忘录模式:onSaveInstanceState
解释器模式:解析Manifest文件
责任链模式:触摸事件传递
策略模式:属性动画的Interpolator
https://xiangzhihong.blog.csdn.net/article/details/53857371
https://juejin.im/entry/5b4b35fe6fb9a04fb401546d
设计模式的6大原则:
1.单一职责原则
2.依赖倒置原则:依赖抽象,不依赖具体
3.开闭原则:拓展开放,修改关闭
4.里氏替换原则:在使用基类的地方可以修改为任意子类
5.接口隔离原则:将庞大臃肿的接口拆分为更小的接口
6.迪米特法则:一个对象对他对象有最少的了解