启动优化:app启动的时候不做耗时操作,尽量把没有必要的初始化代码异步操作
布局优化:减少代码层数,使用约束布局或者时layout优化的标签(include\viewStub\merge)
apk优化:代码进行lint检测优化代码,资源图片使用较小的或者时webp,混淆打包为apk瘦身
性能、电量、网络优化:
1、推送用来代替轮询
2、app处于后台的时候,关闭非必要的数据传输
3、数据传输被拒绝,不要写无限重连的代码
4、后台关闭后,网络请求取消
5、选择相应的定位服务,比如网络定位和GPS定位
6、activity直接使用activityForResult代替广播
7、使用缓存策略
内存优化:
1、for循环的时候,非必要不要创建局部变量,这样会堆中会产品很多临时对象
2、没有用的对象及时回收
3、集合中不要只做只增不减的操作
4、关闭资源:IO流、注册的监听、数据库等
5、不要使用静态、静态变量或者静态内部类
6、图片加载的时候,大图需要压缩或者list中使用缩量图,使用完的图片要及时回收
7、adapter缓存
1、我们的资源没有关闭:注册的监听,数据库,IO流等,对资源进行关闭
2、图片使用完没有回收,对bitmap进行回收
3、内部类持有外部类的引用造成外部类无法回收,内部类使用静态和弱引用解决
4、Activity Context造成的内存溢出,比如在线程中使用线程和Activity生命周期不一致使用静态和弱引用解决,在单例模式中也是持有了外部类导致无法回收使用静态和弱引用解决
5、Handler和内部类一样
6、集合只增不减也会造成,需要合理的增减内容
handler使用静态内部类,这样就不会持有外部Activity的引用导致Activity无法被GC回收,然后使用弱引用这样Activity被回收的时候,我们不去执行代码,然后在Activty销毁的时候removeCallbackAndMessage
1、内存泄漏的过多 2、加载了大图 3、创建了过多的线程
增大内存:Activity在清单文件的节点上增加lagerHeep=true来增加我们的内存
减少内存的使用:1、避免内存泄漏 2、图片使用三方框架 3、业务上的数据可以分批次的加载
ANR:程序无响应5s则会ANR
出现的场景:主线程做了耗时操作、CPU和内存占用多大
解决方法:不在主线程做大量的耗时操作 优化代码减少CPU的处理时间 合理管理内存防止内存泄漏
1、及时关闭资源:IO流、数据量,监听,bitmap复用及时回收
2、单例、Handler、线程、非静态内部类造成的内存泄漏,可以使用静态+弱引用解决
3、集合不要做只增不减的操作
4、合理使用静态成员和静态内部类
约束布局、include、merge、viewStub
1个标签可以实现的就不要用2个标签:drawLeft....
子控件公用的属性可以放在父布局
1、采用二次采样的方法,缩小图片进行存储
2、三级缓存的方式,内存、本地、网络。内存中可以加快渲染速度、本地就是SD卡、网络就是网络访问
3、图片加载的时候需要解码,不用格式的码率不用。耗费的内存也不一样
4、bitmap使用的时候复用、并且及时回收 较少内存的开销
本地:NDK的命令查看
线上:TestIn或者Bugly查看
1、混淆代码,去除无用的资源文件
2、资源文件,图片使用webP或者svg
3、使用.9代替自己绘制的shape
1、优化耗时操作,非必要立马初始化的可以放在子线程中
2、白屏的优化,启动一个空白的Activity跳转到真正的Activty
1、Gradle配置开启混淆
2、混淆文件配置混淆规则
四大组件和View可以不混淆、实体类不可以混淆、第三方根据各自的规则混淆
混淆的目的:减少apk的体积,加大发编译的难度这样更加安全
根据需求,如果是要求展示全部可以不清晰,就压缩后展示或者降低精度在或者修改图片的格式。如果要求质量很高但是不要求全部展示可以进行局部加载然后在拖动展示
1、post的数据和相应的数据进行GZip压缩,减少数据的传输
2、使用图片的加载框架
3、图片的访问携带图片的格式、大小、或者是否压缩的参数访问
4、wifi、数据、弱网、没有网络的时候判断,然后网络越好数据加载的越多
1、对图片进行压缩显示
2、bitmap进行复用
3、bitmap及时回收
1、Bundle
2、文件共享
3、ContentProvider
4、Socket
5、Messenger
6、AIDL
1、应用层:核心的应用会和android系统一起打包,就是手机自己的应用:通讯录、短信、闹钟、日历等。
2、应用架构层:应用层的api使用,包括四大组件,AMS,WMS等
3、应用架构运行层:里面是我们应用架构的底层,里面是C/C++写的Lib库。还有我们的虚拟机
4、Linux层:包含的是Linux底层的东西,包括驱动、网络协议、内存管理等
SharedPreferences是线程安全的,里面是用了大量的 synchronized 进行修饰的。当我们set数据的时候,这个时候如果在进行get或者是set就是需要等待之前操作完成后才执行。commit和apply都是提交数据的方法,他们首先都会缓存到内存中一份,只是commit会同步到磁盘有返回值是否成功,而apply是异步操作的并且没有返回值是否成功
Serializable是Java提供的,Parcelable是安卓提供的
Serializable使用简单,效率慢。Parcelable号称是Serializable速度的10倍但是使用的难一点
Seriaizable适合持久化数据和网络传输,Parcelable适合内存间的传递,因为安卓的每个版本不同,所以他不适合做持久化操作
1、双屏显示
2、后台电量优化、安装策略不同安装效率高
3、文件的私有化和共享,FileProvider
4、通知栏的改变
5、支持VR
ArrayMap底层是双数组,HashMap是数据加链表。在数据的查找方式上,HashMap是根据hash值确定index,而arrayMap是通过二分查找的方式,所以数据大的时候HashMap是占优的
扩容方式不同,HashMap初始值是16内次扩容乘以2。ArrayMap小于4扩容到4,大于等于4扩容到8 以后每次乘以1.5.
扩容的性能上ArrayMap占优,因为他执行的是System.copyArrar(),hashmap每次扩容需要重写计算位置。所以数据量小的情况使用ArrayMap
Arrary内存占用少,HashMap内存占用的大
总的来说就是数据量大的时候选择HashMap,数据量小的时候使用ArrayMap
SparseArray不能完全替代HashMap的,当数据量小于1000并且key是int的时候效率才能优于HashMap. SparseArray的key是int类型底层是2个数据keys和values 因此key不需要装箱和拆箱的操作,也不会出现hash冲突,在数据查询的时候是二分查找效率也还可以。数据结构上也是比HashMap更加单,不需要维护链表了
HttpClient是的api十分庞大,只适用于android 不好维护。
但是httpurlConnection是轻便的灵活的,api使用简单
LifeCycle是JetPack的一个组件,为了监听生命周期的。通过owner和Obsever的方式实现的
AndroidX后CompatActivity的父类ComponentActivity实现了LifeCycleOwer.是现实我们只要实现Observer然后绑定给Activity就实现了
比如我们自定义Observer然后实现onResume,onStop播放和暂停音频,然后Oberser里面标签定义生命周期和实现方法,然后把这个Obsever绑定给Activity就实现了
V1:安卓7.0之前的签名方式,是对条目进行压缩
V2:安卓7.0之后的签名方式,是对所有的字节进行压缩,更安全,安卓规则发生了改变安装效率也高
我们如果只勾选v1签名,安卓7.0后的安装策略不同也会兼容不影响,只勾选v2则7.0之前不能安装。v1v2全勾选才行,7.0后的安装效率也会提高
Android8.0:未知来源安装、通知渠道可以进行分类(不重要的通知)
9.0:刘海屏、全面屏、夜间模式、必须使用Https
10.0:单独沙盒模式、外部无法启动Activty
沙箱模式
后台程序无法启动Activity
WebView
java调用JS:loadUrl加载javaScript
js调用java:URL携带参数的形式,JS桥
1、说说 EventBus 的实现原理?
EventBus是事件总线,实现原理三个方面讲述
1、register(事件的注册):EventBus.getDefault().register(this); 首先getDefault是一个单例模式,然后注册的时候传入this,获取到class.然后通过反射机制拿到订阅者注册的方法(public 参数只能有一个),在EventBus中有2个map的集合分别存储class+eventType和eventType+实体(class+方法),用这个有个集合存储反射的内容。这2个集合就是缓存的作用,当然在添加的时候也会做缓存的判断如果有就不去put了。 订阅者的方法还可以设置线程机制、优先级和粘性事件,粘性事件如果定义则马上发送
2、unRegister(事件的注销):通过class对象,情况上诉的2个集合,对缓存进行清除
3、post(事件的发送):根据发送的数据,线程将其添加到事件的队列中,然后根据事件类型遍历所有订阅者,然后通过反射机制执行所有订阅者订阅的方法
2、谈谈网络请求中的拦截器 - Interceptor 的实现原理和使用场景?
使用场景:重试和重连、日志打印、请求头响应头拦截器,参数拦截器、自定义缓存拦截器
3、谈一谈 Glide 中的缓存机制?
Glide的缓存机制分为弱引用、LurCache、和DiskLurCache(磁盘).内存缓存时为了解决重复引用图片加载到内存中占用内存的问题,磁盘缓存是为了防止重复访问网络的问题
读取的顺序是弱引用->LurCache->DiskLurCache->网络
写入的顺序是网络->diskLurCache->LurCache->弱引用
内存缓存中分为LurCache和弱引用,Glide中有个计数器判断图片是否被引用,当图片被加载的时候引用的是我们的弱引用,当图片没有被引用的时候是缓存在LurCache中的
4、ViewModel 的出现是为了解决什么问题?并简要说说它的内部原理?
1、可以解决Acvity横竖屏切换数据保存的问题,VM的生命周期和Activity是一样的
2、实现数据回收的统一管理,调用onCleared()
帮助管理UI组件的生命周期并存储和管理UI相关的数据。
5、请说说依赖注入框架 ButterKnife 的实现原理?
1、通过注解器在编译期间会生成对应的文件XX_ViewBinding,注解器中会添加特定的注解,查找XX中特定的注解,然后拼接字符串写到XX_ViewBinding中
2、XX_ViewBinding持有XX的引用实现findviewbyid和点击事件
3、XX中对XX_ViewBinding进行初始化完成打通