面试安卓技术相关Android开发积累

[视频笔记] - Android进阶之旅-系统架构

2019-02-11  本文已影响223人  New_X

1.面向对象六大基本原则-网络引擎切换

2.AOP面向切面编程 - 淘宝京东网络处理

AOP:使用AspectJ,在指定位置生成特定的代码,减少工作量,美化工程。
AOP思想:把通用的部分代码统一管理,动态代理,aspecJ 等等

3.UML建模 - View的Touch事件分发流程

4.基础知识扫描 - 反射注解类型

5.编译时注解 - ButterKnife源码分析和手写

ButterKnife:使用apt生成代码,使用到一点反射(ButterKnife.bind()的时候反射得到对应activity) -> 优化private,id不正常。

6.编译时注解 - 绕过微信支付和分享的局限

1.View的事件分发:用两种方式解释(流程图,文字描述)https://www.jianshu.com/p/98d1895c409d
2.源码角度分析invalidate和postInvalidate的区别:
最终都调用了invalidate,但是postInvalidate通过Handler切换到了UI线程,也就意味着可以用来再线程中更新UI
3.简书赞赏的这个View实现:

Image.png

最好的不是自定义View,而是View Group修改onLayout摆放
4.请从源码的角度分析View的绘制流程是从Activity的哪个生命周期开始执行的。
http://www.jianshu.com/p/1075d7d521ec

5.请简述下面三种实例化View的区别,创建RecyclerView 的item下列那种方式最好?还是都可以?(1,3都可以

  1. View.inflate(context,R.layout.item_recycler,null);
    attachToRoot = false, root=null
    // 被添加到了 RecyclerView ,setAdapter的时候会再次添加那么就会报错,因为已经有了一个parent (会抛异常的)
  2. LayoutInflater.from(context).inflate(R.layout.item_recycler,parent);
    attachToRoot = true, root = parent
  3. LayoutInflater.from(context).inflate(R.layout.item_recycler,parent,false);
    attachToRoot =false, root = parent 都会到LayoutInflater里面的inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot)方法
    root为null的时候会给我们创建View的时候设置一个 layoutParams,所以会出现明明设置了match_parent或者具体数值都不行,解决方法是需要parentattachToRoot)为true的时候,parent放入了View,再次添加View会报错

7.Handler通信 - 源码分析和手写Handler框架

子线程中使用 Handler 必须先调用 Looper.prepare(); 不然会报错,我们在主线程中并没有调用过 Looper.prepare(),为什么就不报错?
因为在我们应用启动的时候,ActivityThread 的入口函数 main() 方法中已经帮我们写了这行代码
Looper.prepareMainLooper();// 准备循环

8.单例设计模式 - 强大的 Activity 管理

volatile 关键字
3.1 防止重排序
3.2 线程可见性 - 某一个线程改了公用对象(变量),短时间内另一个线程可能是不可见的,因为每一个线程都有自己的缓存区(线程工作区)

9.Builder设计模式 - 增强版NavigationBar

10.工厂设计模式 - 数据存储的特有方式

11.装饰设计模式 - RecyclerView添加头部和底部

功能:在不使用的继承的方式下,采用装饰设计模式可以扩展一个对象的功能,可以使一个对象变得越来越强大

  1. RecyclerView 添加头部和底部
    RecyclerView 其实是不支持这个头部和底部布局View对象的添加的,但是 ListView 是支持的。我们必须要想办法解决这个问题,当然网络上解决方式很多,
    个人比较赞同是运用 装饰设计模式 去添加头部和底部。ListView 为什么可以添加头部和底部。
    可以完全参考 HeaderViewListAdapter的源码,其实他也是用了装饰设计模式,就是让 ListAdapter 变得更加强大了,让其支持头部和底部的添加
  2. 源码中用到的装饰设计模式
  3. ListView 的 Adapter 源码
  4. ContextWrapper
  5. io的输入输出流

12.模版设计模式 - 自己动手写 OkHttp 的 Dispatcher

定义:一个操作中的算法的框架,而将一些步骤延迟到子类中。使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤(抽象类常用?)
源码中:Activity使用了模板方法
1.什么是钩子:模板设计模式用来控制父类的流程 , 插件化开发hook启动流程

13.策略设计模式 - Log日志输出策略

14.Adapter设计模式 - 打造通用的 IndicatorView

TIM图片20181118230555.png

mSetter.invoke(target, mTmpValueArray);
属性动画说白了就是,android的jni层每隔 16ms 不断的回调 ObjectAnimator 的 doAnimationFrame()方法,
最终其实就是通过反射方法去掉用 View.setXxx(float); 比如 view.SetScaleX(1.0f),view.setTranslationY(0.5f)

15.观察者设计模式 - 观察数据的插入

拉模式:主动 (和写接口请求有什么差别?而且还得返回对象,多庞大,但是Java自带的观察者模式是有主动功能的)
推模式:被动

16. 代理设计模式 - 实现 Retrofit 的 create

动态代理,使用Java的特性,获取方法,在方法总进行预处理或者方法结束的时候处理 -> 利用了AOP的思想,把部分功能抽取出来统一处理

17.原型设计模式 - 订单查询拆分

深拷贝:对象内的对象也需要拷贝
浅拷贝:只拷贝对象,改变拷贝对象内的对象会影响到被拷贝对象

18.迭代器设计模式 - 构建通用 BottomTabNavigationBar

迭代器模式感觉像是适配器模式的特例,多种类都适配成Iterator

19. 责任链设计模式 - QQ微信多用户系统检测

示例:View的事件分发机制
so库编译,推荐linux下使用shell脚本

20.设计模式 - 23种模式总结(前篇)

享元模式:需要大量创建对象的时候,复用对象
命令模式:可以方便的做保存/撤销操作

21.设计模式 - 23种模式总结(后篇)

状态模式:
桥接模式:类与类之间有依赖联系,通过抽象类(咖啡)和接口(佐料)相关联,MVP可利用桥接联系起来
中介者模式:两个类,负责两个功能,一个类改变,需要另一个类发生对应改变,需要通过一个第三方类改变。比如EditText字符长度为0,要把登陆按钮置灰,EditText和Button没联系,所以需要第三方activity作为中介处理。平时其实经常用的,封装两个功能,都在某个类里调用,两个类相互影响。

22.第三方开源库 EventBus - 源码分析和手写

register:为什么需要public的方法?我想是为了其他类访问
为什么需要以类型,不以名称?我想设计者应该是为了存储Map的时候以类别存储同类的,快速找到 -> 可以改造,放到注解?
register找注解的时候用了享元模式
register能用apt编译时生成注解的
subscribe:果然,以类型存储方法 4种线程模型区别 main:主线程执行,Handler切过来/posting:和发送线程一致/backgroud:看看是否是主线程,主线程新建子线程,不是就在当前子线程/aysc:不考虑,就在子线程执行 都用线程池管理
unregister不能直接用Map的remove,因为其他类可能也会用到->(容易掉坑,比如click的时候解绑,传this要带注册者的类名,不然是Click的View,不能解除注册)

EventBus就是两个集合管理:1.Message类 - 封装的被(2.调用类 - 调用类的方法) ->反射调用,

post:

http的多路复用,公司自己写的tcp连接参考了,通过requestId分发
TSL、SSL哪部分用的对称,哪部分非对称?
MD5是对称还是非对称?都不是,MD5只加密不解密

23.第三方开源库 OkHttp - Java网络编程基础

24.第三方开源库 OkHttp - 整体架构和源码分析

25.第三方开源库 OKHttp - 自己动手写表单提交和文件上传

守护线程:JVM的垃圾回收是个守护线程,保证只剩守护线程时才退出
http 请求提交参数传输需要遵循一些规则,空行换行等

26.第三方开源库 OKHttp - 源码精髓之拦截器分析

服务器304的情况并且本地缓存被误删了怎么办?
okhttp基于Socket,那不是能做长连接推送? -> ConnectionPool做了清除不要的连接处理,根据KeepAliveTime
bridge拦截器处理一些基本信息,比如压缩没有,不处理会乱码
okhttp 使用shakehand三次握手还是Socket底层就实现了三次握手? okhttp是SSLSocket shake,三次握手是再linux内核实现的

27.第三方开源库 OKHttp - 上传进度监听和自定义缓存

okhttp下载进度监听:
1.回顾下拦截器,有一个就是处理读流的 Call ServerInterceptor -> 考虑拦截到writeTo
2.找到功能类RequestBody,想要监听,但是是个final,要想到,可以用静态代理,在写之前做些拦截操作
3.BufferedSink没有记录当前写了多少,还需要个静态代理,okhttp有提供ForwardingSink

okhttp添加自定义缓存策略,30s内读取缓存,没网读取缓存
通过拦截器实现,前提,熟悉CacheInterceptor,知道添加addInterceptor和addNetworkInterceptor的区别
addInterceptor:在所有拦截器之前
addNetworkInterceptor:在所有拦截器之后
前面的拦截器最好是用来处理request,后面的最好用来处理response
所以,30s读缓存最好是用addNetworkInterceptor,没网读取缓存用addInterceptor
(okhttp和http协议相关性较大,上述是通过请求头来实现,可以封装,但是一定要懂原理)

28.第三方开源库 OkHttp -文件断点下载

29.第三方开源库 RxJava - 基本使用和源码分析

RxJava:onNext和subscribe的执行顺序搞清楚

.map(new Function<String, String>() {
@Override
public String apply(String s) throws Exception {
Log.e(TAG, "map3 => " + Thread.currentThread().getName());
return s;
}
})
.subscribeOn(Schedulers.mainThread())
.subscribeOn(Schedulers.io()) //这行无意义
.observerOn(Schedulers.mainThread()) //这行无意义
.observerOn(Schedulers.io())
.map(new Function<String, String>() {

@Override
public String apply(String s) throws Exception {
Log.e(TAG, "map4 => " + Thread.currentThread().getName());
return s;
}
})

考虑了下这种多次subscribeOn和的observerOn情况,因为subscribeOn是向上游订阅的,第二层包裹执行到第一层,所以第二层就没意义了
(1)subscribeOn只对上游有效,因为是在订阅过程中传递的,如果有多个,那么只有第一个”生效”(其实对于传递订阅关系都生效了,只是最终事件发射只体现出了最上游subscribeOn的作用)
(2)observerOn只对下游有效,因为它是在事件发射出来之后,回调事件的过程中生效的


image.png

subscribeOn一层层包裹,逐步往上调用,那就只有第一个有用了,observeOn回调时用到,逐步往下回调,所以就最后一个有用了

想要创建主线程Handler,new Handler() 和 new Handler(Looper.getMainLooper())的区别,后者确保不报错,万一是在子线程new Handler()是会报错的

30.第三方开源库 RxJava - 自己动手写事件变换

31.第三方开源库 RxJava - 自己动手线程调度切换

32.第三方开源库 RxJava - Android实际开发场景

33.第三方开源库 Retrofit - 源码设计模式分析

CopyOnWriteArraryList怎么保证线程安全?
1.add等同步操作
2.操作add的时候,先用一个数组加进去,再把加完的复制到原来的数组

Message message = Message.obtain(handler, scheduled); -> 适合简单的调用
第二个参数是个Runnable,如果不为空,查看源码,是从dispatchMessage调用,直接执行Runnable的run方法返回了,完全就不需要handleMessage了

activity.overridePendingTransition(0,0); -----> 处理一些没有界面的activity的时候,不需要动画,避免一些系统默认动画卡顿(比如处理dialog的activity/RxPermission/RxLogin)

Retrofit成功返回对象失败返回""的问题,可以重写callback处理下成功和失败的情况,请求的时候enqueue解决

Java数据结构 第4版

Retrofit:解耦?面向接口,请求可以单独放,转化解析工厂,还能配合RxJava切换线程
实现原理:动态代理获取注解,解析,封装进Okhttp,回调的时候利用转化工厂转化
想想怎么切换线程的 -> Adapter转化okhttpcall为observable

面试:activity里 new Thread() 设置TextView的显示不报错,为什么在子线程中添加sleep就报错了

retrofit核心 解析工厂/转化工厂可自由配置,实现原理,抽象工厂模式,把解析/转化的方法推迟到实现类。默认情况的不解析直接返回requestBody(里面有errorBody,万一body未返回可以看看里面的)

34.第三方开源库 Retrofit - 自己动手写核心架构部分

35.第三方开源库封装 - OkHttp + RxJava + Retrofit

36.第三方开源库 Retrofit - 自己动手优化网络引擎

37.开发模式 MVP - 基础框架搭建分析

MVC演变到MVP,MVP一步步优化

怪不得说dagger解耦了,可以把Presenter单独拎出来,当然用Base类也是一样,其实很多解耦确实是炫技。

38.开发模式MVP - 静态代理和动态扩展

39.项目实战 - 代码架构和运行时架构

动态监测 View 层的接口:
this.getClass().getGenericSuperclass()).getActualTypeArguments()
判断 View层有没有实现对应的View接口

40.项目实战 - 系统架构部分的总结和展望

41.第三方开源库 Glide - 源码分析

Glide通过创建一个Fragment(一个Context只创建一个)来控制图片加载的流程,因为图片加载是耗时的,比如点击了返回,那就需要把图片加载暂停,如果不暂停就耗资源了。公司网络处理也是,不是这个页面就停止请求。
实现是通过LifeCycle,具体得看下(可以试着想想okhttp加上glide的这个性能优化处理?)-> 就是代理模式实现接口
具体怎么onStart/onPause/onStop 调试下 -> 就是利用Fragment绑定到Activity的生命周期这个特点做的,有根据Activity还是FragmentActivity创建app下的还是v4包下的

Glide缓存策略的key是根据很多参数设置的,包括宽高,所以设置的宽高不一样的图片就算取自同个网址,也需要重新请求

Glide用了非常多的接口,比较要区别很多情况(毕竟Decode之类都要区别好几种->其实也不多,但为了拓展吧),走流程画时序图有点麻烦(很多实现地方,可以先打断点看下调用)

Glide写着有点炫技嫌疑,写的是很不错,乍一看很方

Glide的UrlConnection是build的,不同响应码,粗暴的用除以100来处理(2或者3)

Downsamper根据需要的宽高压缩

Parceable怎么实现的,基于内存,和io差不多,读写,协议一样的。这边写进去,那边读出来
LeakCanary怎么实现的

42.Android 多模块多组件开发 - 打造属于自己的路由

43.经验分享 - 深圳社招大厂面试分享

上一篇下一篇

猜你喜欢

热点阅读