Android - 面试题(2)

185 阅读8分钟
ThreadLocal实现原理

image.png

  • Thread类中有一个变量threadLocals,数据类型ThreadLocal.ThreadLocalMap,这个变量用来保存每个线程的私有数据。
  • ThreadLocalMapThreadLocal的内部类,每个数据用Entry保存,entry继承自WeakReference。用ThreadLocal的引用为键进行存储。
  • ThreadLocal中的set方法的实现逻辑,先获取当前线程,取出当前线程的ThreadLocalMap,如果不存在就会创建一个ThreadLocalMap,如果存在就会把当前的threadlocal的引用作为键,传入的参数作为值存入map中。
  • ThreadLocal中get方法的实现逻辑,获取当前线程,取出当前线程的ThreadLocalMap,用当前的threadlocak作为key在ThreadLocalMap查找,如果存在不为空的Entry,就返回Entry中的value,否则就会执行初始化并返回默认的值。
  • ThreadLocal中remove方法的实现逻辑,还是先获取当前线程的ThreadLocalMap变量,如果存在就调用ThreadLocalMap的remove方法。ThreadLocalMap的存储就是数组的实行,因此需要确定元素的位置,找到Entry,把entry的键值对都设为null,最后也Entry也设置为null
ThreadLocal如何解决哈希冲突
当出现Hash冲突时采用线性查找的方式,所谓线性查找,就是根据初始key的
hashcode值确定元素在table数组中的位置,如果发现这个位置上已经有其
他key值的元素被占用,则利用固定的算法寻找一定步长的下个位置,依次判
断,直至找到能够存放的位置。如果产生多次hash冲突,处理起来就没有
HashMap的效率高,为了避免哈希冲突,使用尽量少的threadlocal变量
代理模式和装饰器模式区别?
  1. 装饰器模式强调的是增强自身,在被装饰之后你能够在被增强的类上使用增强后的功能。增强后你还是你,只不过能力更强了而已;代理模式强调要让别人帮你去做一些本身与你业务没有太多关系的职责(记录日志、设置缓存)。代理模式是为了实现对象的控制,因为被代理的对象往往难以直接获得或者是其内部不想暴露出来。
  2. 装饰模式是以对客户端透明的方式扩展对象的功能,是继承方案的一个替代方案;代理模式则是给一个对象提供一个代理对象,并由代理对象来控制对原有对象的引用;
  3. 装饰模式是为装饰的对象增强功能;而代理模式对代理的对象施加控制,但不对对象本身的功能进行增强;
SurfaceView, SurfaceTexture, TextureView的区别
  • SurfaceView是一个View, 有自己对应的Window, 所以在WMS中有自己的WindowState, 在SurfaceFlinger中有自己的Layer.
  • TextureView有自己的BufferQueue, 但是没有自己的Window, 所以他在WMS中并没有自己的WindowState, 也就是说它从属于App的View 树. 但是它有自己的BufferQueue, View树中的其他View并不共用一个BufferQueue. TextureView必须支持硬件加速.
  • SurfaceTexture并不是一个View, 它有自己的BufferQueue, 并且可以用来生成Surface, 传入到SurfaceTexture中的Buffer会被转化为GL纹理, 然后可以把这个纹理交给TextureView或者GLSurfaceView进行显示(纹理只是一堆数据, 必须附加到View上才能被展示)
Android如何实现大图加载?
  • 使用BitmapRegionDecoder
  • 开启复用
  • 计算显示的大小
  • 显示到画布上
  • 手势滑动

可以参考:blog.csdn.net/u011077027/…

HandlerThread原理,优缺点以及试用场景?

原理:

HandlerThread本质上是一个线程类,它继承了Thread。HandlerThread有自己的内部Looper对象,
可以进行loopr循环。通过获取HandlerThread的looper对象传递给Handler对象,可以在
handleMessage()方法中执行异步任务。创建HandlerThread后必须先调用
HandlerThread.start()方法,Thread会先调用run方法,创建Looper对象。
当有耗时任务进入队列时,则不需要开启新线程,在原有的线程中执行耗时任务即可,否则线程阻塞。

优点:

  • HandlerThread优点是异步不会堵塞,减少对性能的消耗。
  • HandlerThread缺点是不能同时继续进行多任务处理,要等待进行处理,处理效率较低。
  • HandlerThread与线程池不同,HandlerThread是一个串队列,背后只有一个线程。

Android中的一个具体的使用场景是IntentService。

Retrofit CreateApi实现原理
  • 首先,使用外观模式统一调用创建网络请求接口实例和网络请求参数配置的方法。
  • 然后,使用动态代理动态地去创建网络请求接口实例。
  • 接着,使用了建造者模式 & 单例模式创建了serviceMethod对象。
  • 再者,使用了策略模式对serviceMethod对象进行网络请求参数配置,即通过解析网络请求接口方法的参数、返回值和注解类型,从Retrofit对象中获取对应的网络的url地址、网络请求执行器、网络请求适配器和数据转换器。
  • 最后,使用了装饰者模式ExecuteCallBack为serviceMethod对象加入线程切换的操作,便于接受数据后通过Handler从子线程切换到主线程从而对返回数据结果进行处理。
Android中为什么主线程不会因为Looper.loop()里的死循环卡死?

可以参考这篇博客: blog.csdn.net/ZytheMoon/a…

https握手过程,如何实现数据加密?客户端如何保证安全实现双重证书校验?

image.png

  1. 客户端发起握手请求,以明文传输请求信息,包含版本信息,加密-套件候选列表,压缩算法候选列表,随机数,扩展字段等信息。
  2. 收到请求后服务端返回协商的信息结果,包括选择使用的协议版本 version,选择的加密套件 cipher suite,选择的压缩算法 compression method、随机数 random_S 以及证书
  3. 客户端验证证书的合法性,包括可信性,是否吊销,过期时间和域名
  4. 客户端使用公匙对对称密匙加密,发送给服务端。(这部分传送的是用证书加密后的随机值,目的是让服务端得到这个随机值,以后客户端和服务端的通信就可以通过这个随机值来进行加密解密了。)
  5. 服务器用私钥解密,拿到对称加密的密匙。(服务端用私钥解密后,得到了客户端传过来的随机值,然后把内容通过该随机值进行对称加密,将信息和私钥通过某种算法混合在一起,这样除非知道私钥,不然无法获取内容,而正好客户端和服务端都知道这个私钥,所以只要加密算法够彪悍,私钥够复杂,数据就够安全。)
  6. 传输加密后的信息,这部分信息就是服务端用私钥加密后的信息,可以在客户端用随机值解密还原。
  7. 客户端解密信息,客户端用之前生产的私钥解密服务端传过来的信息,于是获取了解密后的内容
请你设计一个登录功能,需要注意哪些安全问题
  1. 敏感信息要密文传输(密码)
  2. 在它密码错误达到一定次数时,增加验证码校验
  3. 手机号码验证
  4. 使用Https通信
  5. 用户的每次登录和敏感操作都需要记录日志(包括IP、设备等)
  6. 基于日志做风险提醒,比如用户在进行非常登录地登录、修改密码、登录异常时,可以短信提醒用户
  7. 注册或修改密码时,不允许用户设置弱密码
  8. 防止用户名被遍历。有些App在注册时,在输入完用户名之后,会提示用户名是否存在。这样会存在所有用户名被泄露的风险(遍历该接口即可),需要在交互或逻辑上做限制 。。。。
堆内存,栈内存理解?内存泄漏是发生在堆内存还是栈内存,为什么?

image.png

  • 栈:保存局部变量的值:

    1. 基本数据类型的值。
    2. 保存类的实例,即堆区对象的引用(指针)。
    3. 保存加载方法时的帧。
  • 堆:用来存放动态产生的数据,比如new出来的对象。

    注意创建出来的对象只包含属于各自的成员变量,并不包括成员方法。因为同一个类拥有各自的成员变量,存储在堆中的不同位置,但是同一个类不同实例的他们共享该类的方法,并不是每创建一个对象就把成员方法复制一次。

    内存泄漏发生在堆内存中。

    堆空间里面存储是对象的实例,需要开发者主动创建,垃圾回收主要作用在这部分,回收的一个主要策略是检测堆中的对象在栈空间有无对应的引用。如果没有引用指向它,则会被优先回收,如果有引用指向则不会被回收

BlockCanary原理?

可以参考:blog.zhaiyifan.cn/2016/01/16/…