一、 Java基础
1、集合
1.1 List(有序、可重复)
List里存放的对象是有序的,同时也是可以重复的,List关注的是索引,拥有一系列和索引相关的方法,查询速度快。查询效率高,删除与插入效率低,会引起元素位置变化;
(1) ArrayList 基于动态数组的数据结构,查改效率高, 增删效率低;
(2) LinkedList 基于双向循环链表实现,增删操作效率更高,而查改操作效率较低;
(3) Vector 跟ArrayList相似,线程安全;
1.2 Set(无序、不能重复)
Set里存放的对象是无序,不能重复的,集合中的对象不按特定的方式排序,只是简单地把对象加入集合中。删除和插入效率高,不会引起元素位置变化
(1) HashSet 不允许出现重复元素,不保证集合中元素的顺序,允许包含值为null的元素,最多一个;
(2) ThreeSet 可以实现排序等功能,底层是二叉树
1.3 Map(键值对、键唯一、值不唯一)
Map集合中存储的是键值对,键不能重复,值可以重复。根据键得到值,对map集合遍历时先得到键的set集合,对set集合进行遍历,得到相应的值。
(1) HashMap 根据键的HashCode值存储数据,根据键可以直接获取它的值,具有很快的访问速度,遍历时,取得数据的顺序是完全随机的。因为键对象不可以重复,所以HashMap最多只允许一条记录的键为Null,允许多条记录的值为Null,是非同步的
(2) TreeMap 实现SortMap接口,能够把它保存的记录根据键排序,默认是按键值的升序排序(自然顺序),也可以指定排序的比较器,当用Iterator遍历TreeMap时,得到的记录是排过序的。不允许key值为空,非同步的;
2、继承
从已有的类中派生出已有的类,继承来的类能吸收已有类的非私有属性和方法(行为),并能扩展新的属性和方法。通俗来说,继承就是分为了父类和子类,父类有时也成为超类(super class),子类又成为派生类;子类继承了父类的属性和方法,并且具有了父类所没有的。
4.1 限制
(1)Java的继承只能是单继承,一个子类只能继承一个父类;
(2)Java的继承允许多层继承,即子类又是另一个类的父类(可以理解 为爷爷、爸爸与儿子的关系);
3、多态
指父类的某个方法被子类重写时,可以产生自己的功能行为,同一个操作 作用于不同对象,可以有不同的解释,产生不同的执行结果。
5.1 三个必要条件:继承父类、重写父类的方法和父类的引用指向子类对象;
5.2 作用:消除类型之间的耦合关系, 多个方法在不同对象执行不同的结果;
4、接口
是抽象类的延伸,它允许一个类可以实现多个接口,弥补了抽象类不能多继承的缺陷,接口是对类的描述,使用 interface 关键字来声明。
5、线程池 --待补充
二、 Koltin基础
kotlin语言更简单。能减少代码的冗余以及一些Java不支持的特性
独有的特性:
1.空指针安全
2.操作符重载
3.协程
4.Range 表达式
5.智能转换
6.伴随体
优势:
数据类型 toString, hashcode, equals Setter 和getter都省略
Kotlin支持扩展函数
空指针安全
自带单例(object)
劣势:
没有检查异常、原始类型、 静态成员、 非私有字段、 通配符类型、 三元操作符;
没有明显意义的关键字( internal, crossinline, expect, reified, sealed, open);
Kotlin有没有static 关键字,用伴随体代替;
协程
协程是轻量级线程,创建协程不需要分配新的线程,相反,它使用已经定义好的线程池,智能调度。此外,协程可以挂起和恢复;
三、 Android
各大版本之间的特点:
android 5.0 Material Design视觉工具包、锁屏显示通知
android 6.0 动态权限、文本选择(剪切、复制、全选)
android 7.0 应用分屏、通知栏快捷回复
android 8.0 画中画(视频小窗口)、自适应图标(圆形或方形)
android 9.0 刘海屏、凹凸屏的适配和多摄像头支持
android 10 可折叠设备支持、5G网络、设备标识码和地理位置权限
3.1 网络请求
- 网络
1.1 HTTP与HTTP协议
Get不能大于2kb,执行效率高,不太安全;Post无限制,执行效率低,更安全;
执行效率低的原因是Post需求组装键值对放入header中,get直接拼接即可;
1.2 Okhttp
它内部实现通过一个责任链模式完成,将网络请求的各个阶段封装到各个链条中,实现了各层的解耦。
1.3 Retrofit2 更详细的参考
它并不是网络请求框架,严格说只是对网络请求的一种封装,我们只需要定义一个接口类,在请求方法上加上相应的注解,甚至都不需要实现,就可以实现网络请求。
3.2 开发模式
(1) MVC
Model:针对业务模型建立的数据结构和类(与View无关,只与业务相关)
View:XML/JAVA或者JS+HTML进行页面的显示。Activity/Frgament也承担了View的功能。
Controller:Android的控制层通常在Activity、Fragment之中。本质就是Controller操作Model层的数据,并且将数据返回给View层展示。
缺点:View层和Model层互相耦合,耦合过重,代码量过大,不易于开发和维护。
(2) MVP
Model:对数据和网络等的操作,主要提供数据的存储功能。Presenter需要通过Model存取数据。
View: 负责处理点击事件和视图展示(Activity、Fragment或者某个View控件)
Presenter: View和Model之间的桥梁,从Model检索数据后返回给View层。使得M/V之间不再有耦合关系。
缺点: view层和presenter层,如果有一个逻辑很复杂的页面,接口会有很多,导致维护接口的成本非常大,解决方案是尽可能将一些通用的接口作为基类,其他的接口去继承。
(3) MVVM
View:对应于Activity和XML,负责View的绘制以及与用户交互,它是不能做任何与业务相关的操作。
Model:实体模型,这跟咱们平常定义的Model层是不一样的。
ViewModel:负责完成View与Model之间的交互,负责业务逻辑。它不能做任何与UI相关的操作,也就是不能持有任何View的引用。
ViewModel和Model/View进行了双向绑定。
View发生改变时,ViewModel会通知Model进行更新数据,Model数据更新后,ViewModel会通知View更新显示。支持库Data Binding:能将数据绑定到xml中,现在又引入了ViewModel和LiveData组件用于更方便的实现MVVM
3.3 图片压缩
(1) 常规压缩
①质量压缩
在保持像素的前提下改变图片的位深及透明度(即:通过算法抹掉(同化)图片中的一些某点附近 相近的像素)达到降低质量压缩文件的目的。
②尺寸压缩
通过减少单位尺寸的像素值,真正意义上的降低像素(通过缩放图片像素来减少图片占用内存大小)
③采样率压缩
设置图片的采样率,降低图片像素。好处是不会先将大图片读入内存,大大减少了内存的使用,也不必考虑将大图片读入内存后的释放事宜。 带来的问题是因为采样率是整数,所以不能很好的保证图片的质量。如我们需要的是在2和3采样率之间,用2的话图片就大了一点,但是用3的话图片质量就会有很明显的下降,这样也无法完全满足我的需要。
④通过JIN调用libjpeg库压缩
绕过Android Bitmap API层,自己编码实现—-修复使用哈夫曼算法。
(2). 鲁班压缩
① 核心方法就是thirdCompress(File file),即如何计算得出理想的压缩后宽高,以及图片大小;
② 不足之处: 不能很好的支持多图片压缩,会产生OOM;与RxJava强耦合。
3.5 自定义View
View的绘制流程 和 步骤
3.6 事件分发
基本会遵从 Activity => ViewGroup => View 的顺序进行事件分发,然后通过调用 onTouchEvent() 方法进行事件的处理。我们在项目中一般会对 MotionEvent.ACTION_DOWN,MotionEvent.ACTION_UP,MotionEvent.ACTION_MOVE,MotionEvent.ACTION_CANCEL 分情况进行操作
3.7 性能优化
(1) 启动优化: Application中不要做大量耗时操作,如果必须的话,建议异步做耗时操作
(2) 布局优化:使用合理的控件选择,少嵌套。(合理使用include,merge,viewStub等使用)
(3) Apk优化(资源文件优化,代码优化, lint检查,.9.png, 合理使用shape替代图片,webp等)
(4) 网络优化,电量优化
避免轮询,尽量使用推送。
应用处于后台时,禁用某些数据传输
限制访问频率,失败后不要无限重连
选用合适的定位服务(GPS定位,网络定位,被动定位)
使用缓存
startActivityForResult替代发送广播
(5) 内存优化
循环尽量不使用局部变量
避免在onDraw中创建对象,onDraw会被频繁调用,容易造成内存抖动。循环中创建大的对象,也是如此。
不用的对象及时释放
数据库的cursor及时关闭
Adapter使用缓存
注册广播后,在生命周期结束时反注册
及时关闭流操作
图片尽量使用软引用,较大的图片可以通过bitmapFactory缩放后再使用,并及时recycler。另外加载巨图时不要 使用setImageBitmap或setImageResourse或BitmapFactory.decodeResource,这些方法拿到的都是bitmap的对象,占用内存较大。可以用BitmapFactory.decodeStream方法配合BitmapFactory.Options进行缩放
避免static成员变量引用资源耗费过多实例
避免静态内部类的引用
3.8 异常问题
(1) OOM
out of memory 内存溢出 。
每个进程能够支配的内存是有限的,所以资源要记得使用完及时释放,如果未释放,就有可能造成内存泄漏,内存泄漏达到一定程度 手机就会造成内存溢出。
内存泄漏和内存溢出是不同的,但是过多的内存泄漏会导致内存溢出。
内存溢出的根本原因:
1.应用申请内存的速度超过了gc内存回收的速度。
2.应用申请的内存大小超过了手机的可用内存。
常见根因:
1.加载超大的图片、文件
2.创建大量的对象
优化方法:
1.申请更大的内存,比如多进程、设置manifest中的largeHeap=true等。
2.减少内存使用
①使用优化后的集合对象,分场景使用SpaseArray和HashMap;
②使用微信的mmkv替代sharedpreference;
③使用StringBuilder替代String拼接
④统一带有缓存的基础库,特别是图片库,如果用了两套不一样的图片加载库就会出现2个图片各自维护一套图片缓存
⑤给ImageView设置合适尺寸的图片,列表页显示缩略图,查看大图显示原图
⑥优化业务架构设计,比如省市区数据分批加载,需要加载省就加载省,需要加载市就加载失去,避免一下子加载所有数据
3.避免内存泄漏
(2)ANR和卡顿
(3)过渡绘制
(4)静态代码检测
3.9 屏幕适配
(1) 一般来说主要针对屏幕适配,最小宽度适配和今日头条density适配
(2) 权限适配,安卓6.0的运行时权限,这里有坑,6.0以前,Vivo有i管家进行权限管理,魅族自带有权限管理,还有其他第三方软件进行权限限制,导致权限不可用
(3) 异形屏幕适配,一般来说都是刘海,水滴,挖孔部分不进行使用或者就直接不管不显示缺失部分,可以满足大部分需求,小部分需求需要使用异形部分的需要按手机型号进行特定适配,官网都有适配方法
(4) 安卓系统适配,及时关注新系统新特性,使情况修改targetSdk
(5) 语言,Left Right和Start End,这些适配基本不需要太大关注
(6) “和ios一样”,口才或者脑细胞适配,能说服就下班,不能就加班
3.10 音视频
视频播放器的封装
对三方库GSYVideoPlayer进行二次封装,基于B站的IJKPlayer内核(兼容系统MediaPlayer与EXOPlayer2,支持h263\4\5、Https、concat、rtsp、hls、rtmp、crypto、mpeg等协议, 自定义内容:
(1) 边播放边缓存
(2) 广告和弹幕
(3) 滑动播放(抖音样式)
(4) 列表播放
(5) 实时和非实时播放
(6) 小屏播放
(7) 自定义UI, 包括: 触摸亮度和音量, 快进与快退, 横竖屏切换, 倒计时等等
腾讯直播SDK
(1) 推流和拉流
(2) 消息并发,设置阈值
(3) 自定义ui,点赞等
音频
即时通、听书类app涉及音频开发,通过系统MediaRecord、MediaPlay处理音频的录制、播放。
(1) mp3/wav/ogg/amr/aac等格式
(2) 音量与波浪图同步
(3) 播放进度回调,实时更新ui
(4) 绑定页面生命周期,锁屏播放mediaPlayer.setWakeMode(getApplicationContext(), PowerManager.PARTIAL_WAKE_LOCK
3.11 发版
1.检查数据库版本更新, 重点看下新增字段是否进行升级处理, 防止App崩溃;
2..使用versionName自增,处理强更版本要单独声明一个版本号,防止老版本跨版本更新;
3.开启混淆,保留mapping映射表,若安全方面要求比较高,可以再对APK进行安全加固;
混淆的目的:
1、代码混淆之后会随机生成难易理解的类名、方法名以及属性名,加大反编译的难度;
2、可以对apk进行优化,缩小包的体积;
混淆的步骤:
1、在gradle文件里面打开配置:minifyEnabled true;
2、在proguard-rules.pro 文件里面配置混淆规则;
在配置混淆的时候,需要注意:
1、四大组件以及view可以不进行混淆;
2、实体类不进行混淆;
3、第三方库根据各自的要求配置混淆规则;
4、自定义View不进行混淆
4.引入wall插件, 一键打渠道包, 按渠道上线.
四、 Dart基础
1.没有 「public」「private」等关键字,默认就是公开的,私有变量使用 下划线 _开头;
2.在单线程中是以消息循环机制来运行的,其中包含两个任务队列,一个是“微任务队列” microtask queue,另一个叫做“事件队列” event queue;
3.不存在多线程,提供了一个 类似于新线程,但是不共享内存的独立运行的 worker - isolate;
五、 Flutter
1.StatefulWidget
生命周期:
initState():Widget 初始化当前 State,在当前方法中是不能获取到 Context 的,如想获取,可以试试 Future.delayed()
didChangeDependencies():在 initState() 后调用,State对象依赖关系发生变化的时候也会调用
deactivate():当 State 被暂时从视图树中移除时会调用这个方法,页面切换时也会调用该方法,和Android里的 onPause 差不多。
dispose():Widget 销毁时调用。
didUpdateWidget:Widget 状态发生变化的时候调用。
2.三大树
Widget 仅用于存储渲染所需要的信息。
RenderObject 负责管理布局、绘制等操作。
Element 才是这颗巨大的控件树上的实体。