面试题:你似乎来到了没有知识存在的荒原 - 知乎

字节跳动Android面试题目与答案(2020)

2020年开春最新面试!字节跳动安卓面试题及答案 (已拿到 offer)

Android面试必备26题(阿里腾讯总结)含答案

Android 面试问题记录

做了5年Android,靠着这份面试题跟答案,我从12K变成了30K

Android面试一天一题(Day 37:一套高级工程师的面试题)

2019Android多线程面试题总结

史上最全的2022年最新版Android安卓面试题集锦(含答案+源码)_普通网友的博客-CSDN博客_android面试题及答案

2022年最新版Android安卓面试题+答案精选【二】_普通网友的博客-CSDN博客_安卓面试

【2021版Android面试宝典】,不服不行_普通网友的博客-CSDN博客_android 面试宝典

Android面试宝典 - 技术篇 - 简书

备战2022,Android中高级面试必知必会

Android开发核心知识点笔记 GitHub - hunanmaniu/AndroidNotes: Android.md

Android开发面试笔记  :GitHub - xiangjiana/Android-MS: 2022Android十一位大厂面试真题(含答案) QQ:421869573 ,音视频初-中-高;Flutter,kotlin;Compose;Framework;性能优化;架构等

Kotlin常用Collection集合操作整理_普通网友的博客-CSDN博客_kotlin 集合操作

Android面试题总结——2020.08.24_FreddyChen จุ๊บ的博客-CSDN博客

Android 性能优化之内存泄漏检测以及内存优化(上)_Shawn_Dut的博客-CSDN博客总的上中下

Android开发热门前沿知识,你想学的都在这里_code高级开源的博客-CSDN博客_android 前沿技术

2022Android进阶学习资料,阿里+头条+腾讯大厂Android笔试真题_code高级开源的博客-CSDN博客

(一)背景

(二)Java相关

阿里一面

1.点击图标,应用打开,点击home键,重新进入,Activity生命周期回调

2.service生命周期

(1)通过 startService 启动 Service:

onCreate() >> onStartCommand() >> onDestory()
1.如果 Service 还没有运行,则调用 onCreate()然后调用onStartCommand();

2.如果Service已经运行,则只调用onStartCommand(),所以一个Service的 onStartCommand()方法可能会重复调用多次。

3.调用 stopService 的时候直接 onDestroy(),

4.生命周期和调用者不同,这时 Service 跟启动的 Activity 没有关联,启动后若调用者未调用 stopService 而直接退出,Service 仍会运行。

(2)通过 bindService 绑定 Service:

onCreate >> onBind >> onUnbind >> onDestory。
1.onBind 将返回给客户端一个 IBind 接口实例,IBind 允许客户端回调服务的方法,比如得到 Service 运行的状态或其他操作。

2.生命周期与调用者绑定,那么这个 Service 就跟启动他的进程有关了调用者一旦退出,Service 就会调用 unBind >> onDestory

3.所以调用 bindService 的生命周期为:onCreate --> onBind(只一次,不可多次绑定) --> onUnbind --> onDestory

3.fragment什么时候用

1. 当你有一个activity,想让这个activity根据事件响应可以对应不同的界面时,就可以创建几个fragment,将fragment绑定到该activity

2.Fragment的设计初衷便是为了将布局与代码逻辑一起封装,想想下面这个场景:
一款APP包含界面A和界面B,界面B为界面A的详情。你需要同时适配手机和平板,手机版的操作逻辑为A跳转到B,而平板的布局为AB同一界面,A在左边,B在右边。
这时候最好的方法将A、B都封装为Fragment,手机中直接使用Fragment,平板中设置两个Fragment的布局即可。

4.软引用和弱引用,什么时候用弱引用?

1、软引用是用来描述一些有用但并不是必需的对象,在Java中用java.lang.ref.SoftReference类来表示。对于软引用关联着的对象,只有在内存不足的时候JVM才会回收该对象。因此,这一点可以很好地用来解决OOM的问题,并且这个特性很适合用来实现缓存:比如网页缓存、图片缓存等。软引用可以和一个引用队列(ReferenceQueue)联合使用,如果软引用所引用的对象被JVM回收,这个软引用就会被加入到与之关联的引用队列中

2、弱引用也是用来描述非必需对象的,当JVM进行垃圾回收时,无论内存是否充足,都会回收被弱引用关联的对象。在java中,用java.lang.ref.WeakReference类来表示。

3、弱引用与软引用的区别在于:只具有弱引用的对象拥有更短暂的生命周期。在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。不过,由于垃圾回收器是一个优先级很低的线程, 因此不一定会很快发现那些只具有弱引用的对象。所以被软引用关联的对象只有在内存不足时才会被回收,而被弱引用关联的对象在JVM进行垃圾回收时总会被回收。

4、应用场景:如果一个对象是偶尔的使用,并且希望在使用时随时就能获取到,但又不想影响此对象的垃圾收集,那么应该用 Weak Reference 来记住此对象。或者想引用一个对象,但是这个对象有自己的生命周期,你不想介入这个对象的生命周期,这时候就应该用弱引用,这个引用不会在对象的垃圾回收判断中产生任何附加的影响。
原文链接:https://blog.csdn.net/qq_39192827/article/details/85611873

5.LruCache内部通过什么数据结构实现?最大存贮容量?

三级缓存 DiskLruCache

LruCache的缓存策略

LruCache中维护了一个集合LinkedHashMap,该LinkedHashMap是以访问顺序排序的。当调用put()方法时,就会在结合中添加元素,并调用trimToSize()判断缓存是否已满,如果满了就用LinkedHashMap的迭代器删除队尾元素,即最近最少访问的元素。当调用get()方法访问缓存对象时,就会调用LinkedHashMap的get()方法获得对应集合元素,同时会更新该元素到队头
①设置LruCache缓存的大小,一般为当前进程可用容量的1/8。

Android DiskLruCache完全解析,硬盘缓存的最佳方案

6.activity如何传递信息?

Activity之间传递数据的三种方式详解

1.通过Bundle传递简单数据 
2.通过Serializable方式传递对象 
3.通过Parcelable方式传递对象

7.bundle能传什么类型的数据?

1、基本类型的数据,如int、String、Float等等;

2、自定义的必须实现Serializable(Java中的)和Parceable(Android中的)序列号接口,使用bundle.putSerializable(Key,Value),bundle.putParceable(Key,Value)传递对象

8.parcelable和serialazible的区别?   Android中的IPC机制

Serializable和Parcelable的区别:

  1. Serializable是Java中的序列化接口,其使用起来简单但是开销很大,序列化和反序列化过程需要大量的IO操作。
  2. Parcelable是Android中的序列化方式,因此更加适合Android平台上,它缺点就是使用起来稍微麻烦点(Android studio会自动填充),但它的效率很好,这是Android推荐的序列化方式,因此我们首选Parcelable。

Parcelable和Serializable的作用、效率、区别及选择:

  1. 作du用Serializable的作用是为了保存对象的zhi属性到本地文件、数据库、网dao络流、rmi以方便数据传输,当然这种传输可以是程序内的也可以是两个程序间的。而Android的Parcelable的设计初衷是因为Serializable效率过慢,为了在程序内不同组件间以及不同Android程序间(AIDL)高效的传输数据而设计,这些数据仅在内存中存在,Parcelable是通过IBinder通信的消息的载体。从上面的设计上我们就可以看出优劣了。
  2. 效率及选择Parcelable的性能比Serializable好,在内存开销方面较小,所以在内存间数据传输时推荐使用Parcelable,如activity间传输数据,而Serializable可将数据持久化方便保存,所以在需要保存或网络传输数据时选择Serializable,因为android不同版本Parcelable可能不同,所以不推荐使用Parcelable进行数据持久化。
  3. 编程实现对于Serializable,类只需要实现Serializable接口,并提供一个序列化版本id(serialVersionUID)即可。而Parcelable则需要实现writeToParcel、describeContents函数以及静态的CREATOR变量,实际上就是将如何打包和解包的工作自己来定义,而序列化的这些操作完全由底层实现。

10.Android handler和looper源码?

Android 源码分析 —— Handler、Looper 和 MessageQueue - 知乎

Android Handler机制(三)---Looper源码解析 - 超超boy - 博客园

11.loop()方法阻塞,为什么不影响事件分发?

Android中为什么主线程不会因为Looper.loop()方法造成阻塞

主要原因有2个

  1. epoll模型 
    当没有消息的时候会epoll.wait,等待句柄写的时候再唤醒,这个时候其实是阻塞的。

  2. 所有的ui操作都通过handler来发消息操作。 
    比如屏幕刷新16ms一个消息,你的各种点击事件,所以就会有句柄写操作,唤醒上文的wait操作,所以不会被卡死了。

12.Android 事件分发?

Android事件分发机制详解:史上最全面、最易懂 - 简书

Android事件分发机制,大表哥带你慢慢深入 - 简书

13.谈谈你对安卓签名的理解

  1. 每个应用都必须签名
  2. 应用可以被不同的签名文件签名(如果有源代码或者反编译后重新编译)
  3. 同一个应用如果签名不同则不能覆盖安装

14.请解释安卓为啥要加签名机制?

为什么要签名

发送者的身份认证:由于开发商可能通过使用相同的 Package Name 来混淆替换已经安装的程序,以此保证签名不同的包不被替换
保证信息传输的完整性:签名对于包中的每个文件进行处理,以此确保包中内容不被替换
防止交易中的抵赖发生:Market(应用市场)对软件的要求
给apk签名可以带来以下好处:

应用程序升级:能无缝升级到新的版本,必须要同一个证书进行签名并且包名称要相同。(如果证书不同,可能会被系统认为是不同的应用)
应用程序模块化:Android系统可以允许同一个证书签名的多个应用程序在一个进程里运行(系统实际把他们作为一个单个的应用程序),此时就可以把我们的应用程序以模块的方式进行部署,而用户可以独立的升级其中的一个模块
代码或者数据共享:Android提供了基于签名的权限机制,那么一个应用程序就可以为另一个以相同证书签名的应用程序公开自己的功能。

签名的说明

所有的应用程序都必须有数字证书:Android 系统不会安装一个没有数字证书的应用程序
Android 程序包使用的数字证书可以是自签名的:不需要一个权威的数字证书机构签名认证
使用一个合适的私钥生成的数字证书来给程序签名:如果要正式发布一个 Android 应用,必须使用一个合适的私钥生成的数字证书来给程序签名,而不能使用 adt 插件或者 ant 工具生成的调试证书来发布
数字证书都是有有效期的:Android 只是在应用程序安装的时候才会检查证书的有效期。如果程序已经安装在系统中,即使证书过期也不会影响程序的正常功能

15.视频加密传输

16.App 是如何沙箱化,为什么要这么做?

17.权限管理系统(底层的权限是如何进行 grant 的)?

  1. permission 的初始化:是指 permission 的向系统申请,系统进行检测并授权,并建立相应的数据结构。
  2. 权限检查:Android framework 中提供了一些接口用来对外来的访问(包括自己)进行权限检查 。 这些接口 主要通过 ContextWrapper 提供,具体实现在 ContextImpl 中 。ContextImpl.java 中提供的 API ,其实都是由 ActivityManagerService 中的如下几个接口进行的封装。

其中有一个checkPermission() // 主要用于一般的 permission 检查

checkPermission 的实现分析

  1. 如果传入的 permission 名称为 null ,那么返回 PackageManager.PERMISSION_DENIED 。
  2. 判断调用者 uid 是否符合要求 。
  3. 如果通过 2 的检查后,再 调用 PackageManagerService.checkUidPermission ,判断 这个 uid 是否拥有相应的权限
  4. 权限校验之后,应给分发了

18.操作系统中什么是堆栈   

操作系统,堆栈(stack),堆(heap),详解 - qq_42034205的博客 - CSDN

1.堆:什么是堆?又该怎么理解呢?

  1. 堆(heap)是一种数据结构,堆控制一段自己的存储空间,叫做堆空间。
  2. 堆是在程序运行时申请的动态内存,而不是在程序编译时,申请某个大小的内存空间。
  3. 堆是应用程序在运行的时候请求操作系统分配给自己内存,一般是申请/给予的过程。

2. 栈(堆栈):什么是堆栈?又该怎么理解呢?

  1. 栈(stack)又名堆栈是操作系统在建立某个进程时或者线程,为这个线程建立的存储区域,在编译的时候可以指定需要的栈的大小
  2. 栈,它是一种运算受限的线性表。其限制是仅允许在表的一端进行插入和删除运算。这一端被称为栈顶,相对地,把另一端称为栈底。
  3. 栈好比一个桶,后放进去的先拿出来,它下面本来有的东西要等它出来之后才能出来(先进后出)。

19.为什么内存要在堆栈中分配

内存分配方式有三种:

  1. 从静态存储区域分配。内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。例如全局变量,static变量。
  2. 在栈上创建。在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。
  3. 从堆上分配,亦称动态内存分配。程序在运行的时候用malloc或new申请任意多少的内存,程序员自己负责在何时用free或delete释放内存。动态内存的生存期由我们决定,使用非常灵活,但问题也最多。

20.反射:

插件化知识详细分解及原理 之代理,hook,反射_Loong.xu的博客-CSDN博客

JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为Java语言的反射机制

21.Java中四种引用

1、强引用

  如果一个对象具有强引用,它就不会被垃圾回收器回收。即使当前内存空间不足,JVM也不会回收它,而是抛出 OutOfMemoryError 错误,使程序异常终止。如果想中断强引用和某个对象之间的关联,可以显式地将引用赋值为null,这样一来的话,JVM在合适的时间就会回收该对象。

String str = "hello";    // 强引用
str = null;              // 取消强引用
2、软引用
在使用软引用时,如果内存的空间足够,软引用就能继续被使用,而不会被垃圾回收器回收;只有在内存空间不足时,软引用才会被垃圾回收器回收。
SoftReference<String> softName = new  SoftReference<>("张三");
3、弱引用
具有弱引用的对象拥有的生命周期更短暂。因为当 JVM 进行垃圾回收,一旦发现弱引用对象,无论当前内存空间是否充足,都会将弱引用回收。不过由于垃圾回收器是一个优先级较低的线程,所以并不一定能迅速发现弱引用对象。
WeakReference<String> weakName = new WeakReference<String>("hello");
4、虚引用  顾名思义,就是形同虚设,如果一个对象仅持有虚引用,那么它相当于没有引用,在任何时候都可能被垃圾回收器回收。虚引用必须和引用队列关联使用,当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会把这个虚引用加入到与之关联的引用队列中。程序可以通过判断引用队列中是否已经加入了虚引用,来了解被引用的对象是否将要被垃圾回收。如果程序发现某个虚引用已经被加入到引用队列,那么就可以在所引用的对象的内存被回收之前采取必要的行动。
ReferenceQueue<String> queue = new ReferenceQueue<String>();
PhantomReference<String> pr = new PhantomReference<String>(new String("hello"), queue);
详解连接:Java如何有效地避免OOM:善于利于软引用和弱引用

22.Java 的泛型

java 泛型详解

泛型,即“参数化类型”;泛型提供了编译时类型安全监测机制,该机制允许程序员在编译时监测非法的类型。使用泛型机制编写的程序代码要比那些杂乱地使用Object变量,然后再进行强制类型转换的代码具有更好的安全性和可读性。泛型对于集合类尤其有用,例如,ArrayList就是一个无处不在的集合类。

 

23.final、finally、finalize 的区别

  • final   在java中,final可以用来修饰类,方法和变量
  • finally  finally作为异常处理的一部分,它只能用在try/catch语句中,并且附带一个语句块,经常被用在需要释放资源的情况下
  •  finalize  finalize()是在java.lang.Object里定义的,每一个对象都有这么个方法。这个方法在gc启动,该对象被回收的时候被调用。其实gc可以回收大部分的对象(凡是new出来的对象,gc都能搞定,一般情况下我们又不会用new以外的方式去创建对象),所以一般是不需要程序员去实现finalize的。 特殊情况下,需要程序员实现finalize,当对象被回收的时候释放一些资源,比如:一个socket链接,在对象初始化时创建,整个生命周期内有效,那么就需要实现finalize,关闭这个链接。 使用finalize还需要注意一个事,调用super.finalize();一个对象的finalize()方法只会被调用一次,而且finalize()被调用不意味着gc会立即回收该对象,所以有可能调用finalize()后,该对象又不需要被回收了,然后到了真正要被回收的时候,因为前面调用过一次,所以不会调用finalize(),产生问题。 所以,推荐不要使用finalize()方法,它跟析构函数不一样。

24.接口、抽象类的区别

共同点如下:
1) 都是上层的抽象层。
2) 都不能被实例化
3) 都能包含抽象的方法,这些抽象的方法用于描述类具备的功能,但是不比提供具体的实现。
他们的区别如下:
1) 在抽象类中可以写非抽象的方法,从而避免在子类中重复书写他们,这样可以提高代码的复用性,这是抽象类的优势;接口中只能有抽象的方法。
2) 一个类只能继承一个直接父类,这个父类可以是具体的类也可是抽象类;但是一个类可以实现多个接口。

25.SurfaceView、TextureView、GLSurfaceView 区别及使用场景

Android 5.0中的SurfaceTexture,TextureView, SurfaceView和GLSurfaceView

View: 显示视图,内置画布,提供了图形绘制函数、触屏事件、按键事件函数等,必须在UI主线程内更新画面,速度较慢;

SurfaceView: 基于view视图进行拓展的视图类,更适合2D游戏的开发,是view的子类,使用了双缓冲机制,即:允许在子线程中更新画面,所以刷新界面速度比view快。

GLSurfaceView: 基于SurfaceView视图再次进行拓展的视图类,在SurfaceView基础上封装了EGL环境管理以及render线程,专用于3D游戏开发的视图。是SurfaceView的子类,openGL专用。

TextrueView: 前面的SurfaceView的工作方式是创建一个置于应用窗口之后的新窗口,脱离了Android的普通窗口,因此无法对其应用变换操作(平移、缩放、旋转等),而TextureView则解决了此问题,Android4.0引入。

应用场景:

  • 1 被动更新画面的。比如棋类,这种用View就好了。因为画面的更新是依赖于 onTouch 来更新,可以直接使用 invalidate。 在这种情况下,这一次Touch和下一次的Touch需要的时间比较长些,不会产生影响。
  • 2 主动更新。比如一个人在一直跑动。这就需要一个单独的thread不停的重绘人的状态,避免阻塞main UI thread。所以显然view不合适,需要SurfaceView来控制。
  • 3.对于一些3D游戏来说,为了追求极致的性能和帧率,可以使用GLSurfaceView。其本身就封装了一些OpenGL ES的API, 通过着色器可以达到很多View难以达到的效果。
  • 4.SurfaceView窗口刷新的时候不需要重绘应用程序的窗口(android普通窗口的视图绘制机制是一层一层的,任何一个子元素或者是局部的刷新都会导致整个视图结构全部重绘一次,因此效率非常低下,不过满足普通应用界面的需求还是绰绰有余),但是SurfaceView也有一些非常不便的限制。因为SurfaceView的内容不在应用窗口上,所以不能使用变换(平移、缩放、旋转等),所以如果是对于视频播放器或者相机应用的开发,TextureView更加适合。

26.动画、差值器、估值器(Android中的View动画和属性动画 - 简书、Android 动画 介绍与使用)

网络

Http协议总结(面试)

HTTP协议【详解】——经典面试题

1、网络框架对比和源码分析

2、网络七层协议有哪些?

OSI七层模型

  • 1、应用层:直接与用户之间交互的,包括用户的软件,网站等
  • 2、表示层:使用这个软件或者网站可以看到的数据:图片文字等
  • 3、会话层:保存登陆连接状态,在电脑中以cookie保存
  • ---------------------------------------------------------------------
  • 有的分类方式也会将上面三层分为一层,统一称为应用层
  • ---------------------------------------------------------------------
  • 4、传输层:选择协议TCP/UDP,相当于给数据加上报头;[TCP][数据]
  • 5、网络层:通过IP路径寻址,同时又对数据进行封装;[IP][[TCP][数据]]
  • 6、数据链传输层;使用Mac地址寻址,又进行了数据封装;【mac地址】【[IP][[TCP][数据]]】
  • 7、物理层;将上面得到的数据转化为电信号或者光信号
  • ------------------------------------------------------------------------
  • 这四层都有socket模块帮助我们辅助完成

1、Http 和 Https 的区别?Https为什么更加安全?

Https特点:基于HTTP协议,通过SSL或TLS提供加密处理数据、验证对方身份以及数据完整性保护

2、HTTPS的连接建立流程

  1. client向server发送请求https://baidu.com,然后连接到server的443端口,发送的信息主要是随机值1和客户端支持的加密算法。
  2. server接收到信息之后给予client响应握手信息,包括随机值2和匹配好的协商加密算法,这个加密算法一定是client发送给server加密算法的子集。
  3. 随即server给client发送第二个响应报文是数字证书。服务端必须要有一套数字证书,可以自己制作,也可以向组织申请。区别就是自己颁发的证书需要客户端验证通过,才可以继续访问,而使用受信任的公司申请的证书则不会弹出提示页面,这套证书其实就是一对公钥和私钥。传送证书,这个证书其实就是公钥,只是包含了很多信息,如证书的颁发机构,过期时间、服务端的公钥,第三方证书认证机构(CA)的签名,服务端的域名信息等内容。
  4. 客户端解析证书,这部分工作是由客户端的TLS来完成的,首先会验证公钥是否有效,比如颁发机构,过期时间等等,如果发现异常,则会弹出一个警告框,提示证书存在问题。如果证书没有问题,那么就生成一个随即值(预主秘钥)。
  5. 客户端认证证书通过之后,接下来是通过随机值1、随机值2和预主秘钥组装会话秘钥。然后通过证书的公钥加密会话秘钥。
  6. 传送加密信息,这部分传送的是用证书加密后的会话秘钥,目的就是让服务端使用秘钥解密得到随机值1、随机值2和预主秘钥。
  7. 服务端解密得到随机值1、随机值2和预主秘钥,然后组装会话秘钥,跟客户端会话秘钥相同。
  8. 客户端通过会话秘钥加密一条消息发送给服务端,主要验证服务端是否正常接受客户端加密的消息。
  9. 同样服务端也会通过会话秘钥加密一条消息回传给客户端,如果客户端能够正常接受的话表明SSL层连接建立完成了。

3、解释一下 三次握手 和 四次挥手

socket底层实现原理 (TCP三次握手四次挥手)

三次握手,是指建立一个TCP连接时,需要客户端和服务器总共发送3个包。三次握手的目的是连接服务器指定端口,建立TCP连接,并同步连接双方的序列号和确认号并交换TCP窗口大小信息。

SYN(synchronous)是同步标志;ACK (Acknowledgement)是确认标志,seq是序列号

  • 第一次握手:客户端发送一个TCP的SYN标志位置1的包,指明客户打算连接的服务器的端口,以及初始序号X,保存在包头的序列号字段里。
  • 第二次握手:服务器发回确认包(ACK)应答。即SYN标志位和ACK标志位均为1同时,将确认序号设置为客户的序列号加1以,即X+1。
  • 第三次握手:客户端再次发送确认包(ACK) SYN标志位为0,ACK标志位为1。并且把服务器发来ACK的序号字段+1,放在确定字段中发送给对方.并且在数据段放写序列号的+1。

四次挥手(Four-Way Wavehand)即终止TCP连接,就是指断开一个TCP连接时,需要客户端和服务端总共发送4个包以确认连接的断开

  • (1)第一次挥手:Client发送一个FIN,用来关闭Client到Server的数据传送,Client进入FIN_WAIT_1状态。
  • (2)第二次挥手:Server收到FIN后,发送一个ACK给Client,确认序号为收到序号+1(与SYN相同,一个FIN占用一个序号),Server进入CLOSE_WAIT状态。
  • (3)第三次挥手:Server发送一个FIN,用来关闭Server到Client的数据传送,Server进入LAST_ACK态。
  • (4)第四次挥手:Client收到FIN后,Client进入TIME_WAIT状态,接着发送一个ACK给Server,确认序号为收到序号+1,Server进入CLOSED状态,完成四次挥手。

4、TCP 和 UDP的区别

socket底层实现原理 (TCP/UDP)

UDP是面向无连接、传输不可靠、用于传输少量数据(数据包模式)、速度快的传输层协议。注意,UDP传输的是数据报包,而TCP是流

5、Cookie和Session

Cookie和Session详解

  • Session 是保存在服务端,用于标识用户

  • Cookie 是保存在客户端的,浏览器端

  • Cookie使用HTTP Header 传递数据

    Cookie机制定义了两种Header :Set-Cookie Header 和Cookie Header:Set-Cookie Header 包含于Web服务器的响应头(Response Header)中;Cookie Header 包含在浏览器客户端请求头(Reguest Header)中

  • 绝大部分情况都是用 Cookie 来实现Session跟踪的 ,在 Cookie 里面记录了一个Session ID

  • Session ID 是一种机制,不同的环境有不同的叫法 比如: java web 是 JSESSIONID

  • okhttp等使用:

    1. classicApplication.getHeadersMap().put("Cookie","SESSION="+sessionId);//01866fbe-725c-482b-aca1-dcd32a6dcfe2

    2. // .addInterceptor(httpCookiesInterceptor)

6、DNS是什么?

DNS的全称是Domain Name System。它负责把FQDN(就是以"."分隔结尾的名字)翻译成一个IP。

最初的DNS系统使用的是一个巨大的hosts.txt文件,最终发展到了现在的分布式数据库。DNS系统是一个分布式的数据库,当一个数据库发现自己并没有某查询所需要的数据的时候,它将把查询转发出去,而转发的目的地通常是根服务器,根服 务器从上至下层层转发查询,直到找到目标为止。DNS还有一个特点就是使用高速缓存,DNS把查询过的数据缓存在某处,以便于下次查询时使用。

DNS报文定义了一个既可以查询也可以响应的报文格式:

  • 最前面的16个bit唯一的标示了问题号码,用于查询端区别自己的查询。
  • 紧接着的16个bit又可以做进一步的细分,标示了报文的性质和一些细节,比如说是查询报文还是响应报文,需要递归查询与否(一般服务器都支持递归查询,而且不需要任何设置,BIND就是这样)
  • 查询问题后面有查询类型,包括A,NS,CNAME,PTR,HINFO,MX,如果熟悉BIND的话,就知道在zong的配置文件里面,每一条记录都记载了各自的类型,比如A就是IP地址,NS就是名字服务器。
  • 响应报文可以回复多个IP,也就是说,域名可以和多个IP地址对应,并且有很多CNAME。

7、DNS解析过程

浅析DNS域名解析过程

8、HTTPS实现原理:SSL建立链接过程

  1. client向server发送请求https://baidu.com,然后连接到server的443端口,发送的信息主要是随机值1和客户端支持的加密算法。
  2. server接收到信息之后给予client响应握手信息,包括随机值2和匹配好的协商加密算法,这个加密算法一定是client发送给server加密算法的子集。
  3. 随即server给client发送第二个响应报文是数字证书。服务端必须要有一套数字证书,可以自己制作,也可以向组织申请。区别就是自己颁发的证书需要客户端验证通过,才可以继续访问,而使用受信任的公司申请的证书则不会弹出提示页面,这套证书其实就是一对公钥和私钥。传送证书,这个证书其实就是公钥,只是包含了很多信息,如证书的颁发机构,过期时间、服务端的公钥,第三方证书认证机构(CA)的签名,服务端的域名信息等内容。
  4. 客户端解析证书,这部分工作是由客户端的TLS来完成的,首先会验证公钥是否有效,比如颁发机构,过期时间等等,如果发现异常,则会弹出一个警告框,提示证书存在问题。如果证书没有问题,那么就生成一个随即值(预主秘钥)。
  5. 客户端认证证书通过之后,接下来是通过随机值1、随机值2和预主秘钥组装会话秘钥(这个会话密钥属于对称加密)。然后通过证书的公钥加密会话秘钥。
  6. 传送加密信息,这部分传送的是用证书加密后的会话秘钥,目的就是让服务端使用秘钥解密得到随机值1、随机值2和预主秘钥。
  7. 服务端解密得到随机值1、随机值2和预主秘钥,然后组装会话秘钥,跟客户端会话秘钥相同。
  8. 客户端通过会话秘钥加密一条消息发送给服务端,主要验证服务端是否正常接受客户端加密的消息。
  9. 同样服务端也会通过会话秘钥加密一条消息回传给客户端,如果客户端能够正常接受的话表明SSL层连接建立完成了。

10.HTTP报文结构

关于HTTP协议,一篇就够了

Http协议由什么组成

请求报文包括三部分:

  • (1).请求行:包含请求方法,URI,HTTP版本协议
  • (2).请求首部字段
  • (3).请求内容实体

响应报文包含三部分:

  • (1).状态行:包含HTTP版本,状态码,状态码原因短语
  • (2).响应首部字段
  • (3).响应内容实体

11.HTTP与HTTPS的区别以及如何实现安全性

http是应用层协议,它会将要传输的数据以明文的方式给传输层,这样显然不安全。https则是在应用层与传输层之间又加了一层,该层遵守SSL/TLS协议,用于数据加密。

12.如何验证证书的合法性?

  1. 证书包含以下信息:申请者公钥、申请者的组织信息和个人信息、签发机构 CA 的信息、有效时间、证书序列号等信息的明文,同时包含一个签名;

  2. 签名的产生算法:首先,使用散列函数计算公开的明文信息的信息摘要,然后,采用 CA 的私钥对信息摘要进行加密,密文即签名;

客户端在对服务器say hello之后,服务器将公开密钥证书发送给客户端,注意这个证书里面包含了公钥+各种信息+签名(私钥对各种信息加密后生成签名),客户端收到公开密钥证书后,相当于收到了一个包裹里面有公钥+各种信息+签名,怎么样使用这三个数据来校验尼,很简单,公钥加密,私钥解,私钥加密公钥也可以解,只要利用公钥对签名进行解密,然后最和各种信息做比较就可以校验出证书的合法性

13.https中哪里用了对称加密,哪里用了非对称加密,对加密算法(如RSA)等是否有了解?

参考8

14.client如何确定自己发送的消息被server收到?

15.谈谈你对WebSocket的理解

  • 目的:即时通讯,替代轮询
  • 原理:WebSocket同HTTP一样也是应用层的协议,但是它是一种双向通信协议,是建立在TCP之上的。一开始的握手需要借助HTTP请求完成

16.WebSocket与socket的区别  :   Socket是传输控制层协议,WebSocket是应用层协议

Http协议总结(面试)
17.http和https区别

http1.0 http1.0 http2.0的特点和改进

  • HTTP 2.0带来哪些新特性_浴盆的博客-CSDN博客
  • 多路复用:允许同时通过单一的HTTP/2连接发起多重的请求-响应消息
  • 二进制分帧 :关键之一就是在应用层(HTTP/2)和传输层(TCP or UDP)之间增加一个二进制分帧层
  • 头部压缩:HTTP2.0encoder来减少需要传输的header大小,
  • 服务器推送:服务器除了对最初请求的响应外,服务器还可以额外的向客户端推送资源,而无需客户端明确的请求。

18.如何改进http,提高响应速度,减少请求时间

Http[s]请求慢的解决办法(DNS、携带数据、直接访问 IP)
19.http缓存 Http缓存机制与原理_闹屋的博客-CSDN博客

算法

1.查找算法有哪些  

查找算法总结 - 深夜十二点三十三 - 博客园

二分查找、插值查找和斐波那契查找
2.什么是时间复杂度    

算法(一)时间复杂度

时间复杂度:评估执行程序所需的时间。可以估算出程序对处理器的使用程度。
空间复杂度:评估执行程序所需的存储空间。可以估算出程序对计算机内存的使用程度。

3.二分查找的时间复杂度是什么

O(logn)

4、断点续传的实现&设计一个下载器

首先定义下载的相关类,存储url、文件总大小、已经下载的文件大小等信息:

public class FileInfo implements Serializable{private String url; //URLprivate int length; //长度或结束位置private int start; //开始位置private int now;//当前进度
//构造方法,set/get略
}

启动开始下载的监听事件:

//开始按钮逻辑,停止逻辑大致相同
strat.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {Intent intent = new Intent(MainActivity.this,DownLoadService.class);intent.setAction(DownLoadService.ACTION_START);intent.putExtra("fileUrl",info);startService(intent);}
});

使用intent来启动service。

然后在Service中的onStartCommand()中,将FileInfo对象从Intent中取出,如果是开始命令,则开启一个线程,根据该url去获得要下载文件的大小,将该大小写入对象并通过Handler传回Service,同时在本地创建一个相同大小的本地文件。暂停命令最后会讲到。

public void run() {HttpURLConnection urlConnection = null;RandomAccessFile randomFile = null;try {URL url = new URL(fileInfo.getUrl());urlConnection = (HttpURLConnection) url.openConnection();urlConnection.setConnectTimeout(3000);urlConnection.setRequestMethod("GET");int length = -1;if (urlConnection.getResponseCode() == HttpStatus.SC_OK) {//获得文件长度length = urlConnection.getContentLength();}if (length <= 0) {return;}//创建相同大小的本地文件File dir = new File(DOWNLOAD_PATH);if (!dir.exists()) {dir.mkdir();}File file = new File(dir, FILE_NAME);randomFile = new RandomAccessFile(file, "rwd");randomFile.setLength(length);//长度给fileInfo对象fileInfo.setLength(length);//通过Handler将对象传递给ServicemHandle.obtainMessage(0, fileInfo).sendToTarget();} catch (Exception e) {e.printStackTrace();} finally {  //流的回收逻辑略}}}

获取到文件的大小之后就可以开始下载了,当用户点击了暂停之后将截止暂停时对应的已下载进度、url等信息保存起来(另外的文件或数据库)并结束下载进程,当用户点击了继续下载的按钮后从文件或数据库中将之前的下载进度读取出来,使用setRequestProperty告知服务器从哪里开始传递数据,传递到哪里结束,然后继续下载,直至最终下载完成。

主要涉及的点:

  • 开启service,service中开启下载线程
  • getContentLength()获取文件总大小
  • RandomAccessFile(file, “rwd”)创建指定大小的文件和随机读写seek(start)
  • 保存下载的url和当前的下载进度等信息
  • setRequestProperty告诉服务器数据传送的起点

3.2、技能储备

3.2.1Java

3.2.1.0、 SparseArray

当新建一个key为整型的HashMap时,会出现如下的提示信息,推荐使用SparseArray来替代HashMap:

接下来就来介绍下SparseArray:

a.数据结构:又称稀疏数组,内部通过两个数组分别存储key和value,并用压缩的方式来存储数据

b.优点:可替代key为int、value为Object的HashMap,相比于HashMap

· 能更节省存储空间

· 由于key指定为int,能节省int和Integer的装箱拆箱操作带来的性能消耗

· 扩容时只需要数组拷贝工作,而不需重建哈希表

c.适用场景:数据量不大(千以内)、空间比时间重要、需要使用Map且key为整型;不适合存储大容量数据,此时性能将退化至少50%

d.使用

添加:public void put(int key, E value)

删除:

  • · public void delete(int key)
  • · public void remove(int key)实际上内部会调用delete方法

查找:

  • · public E get(int key)
  • · public E get(int key, E valueIfKeyNotFound)可设置假设key不存在时默认返回的value
  • · public int keyAt(int index)获取相应的key
  • · public E valueAt(int index)获取相应的value

e.get/put过程:元素会按照key从小到大进行存储,先使用二分法查询key对应在数组中的下标index,然后通过该index进行增删查。源码分析见SparseArray解析。

3.2.1.1、HashMap和Hashtable区别?

HashMap和HashTable

这个一定要去看源码!看源码!看源码!实在看不下去的可以上网看别人的分析。简单总结有几点:

1.HashMap支持null Key和null Value;Hashtable不允许。这是因为HashMap对null进行了特殊处理,将null的hashCode值定为了0,从而将其存放在哈希表的第0个bucket。

2.HashMap是非线程安全,HashMap实现线程安全方法为Map map = Collections.synchronziedMap(new HashMap());Hashtable是线程安全

3.HashMap默认长度是16,扩容是原先的2倍;Hashtable默认长度是11,扩容是原先的2n+1

4.HashMap继承AbstractMap;Hashtable继承了Dictionary

扩展,HashMap 对比 ConcurrentHashMap ,HashMap 对比 SparseArray,LinkedArray对比ArrayList,ArrayList对比Vector

3.2.1.2、Java垃圾回收机制

Java虚拟机二:垃圾回收机制_刘镓旗的博客-CSDN博客

需要理解JVM,内存划分——方法区、内存堆、虚拟机栈(线程私有)、本地方法栈(线程私有)、程序计数器(线程私有), 理解回收算法——标记清除算法、可达性分析算法、标记-整理算法、复制算法、分代算法,优缺点都理解下。

3.2.1.3、类加载机制

这个可以结合 热修复 深入理解下。

Java虚拟机四:类加载机制

Android动态加载技术基础2之类加载

类加载过程:

加载(Loading)、验证(Verification)、准备(Preparation)、解析(Resolution)、初始化(Initialization)、使用(Using)、和卸载(Unloading)这7个阶段,其中验证、准备和解析3个统称为连接(Linking)

3.2.1.4、线程和线程池,并发,锁等一系列问题

这个可以扩展下 如何自己实现一个线程池?

ThreadPoolExecutor配置细节(自定义线程池)

Android的线程和线程池(包含HandlerThread、IntentService)

线程和线程池

在操作系统中,线程是操作系统调度的最小单元,同时线程又是一种受限的系统资源,即线程不可能无限制的产生,并且线程的创建和销毁都会有相应的开销。所以此时线程池就派上了用场。一个线程池中会缓存一定数量的线程,通过线程池就可以避免因为频繁创建和销毁线程所带来的系统开销。
线程池主要有以下三个优点

  • 重用线程池中的线程,避免因为线程的创建和销毁所带来的的性能开销。
  • 有效控制线程池的最大并发数,避免大量的线程之间因互相抢占系统资源而导致的阻塞现象。
  • 能够对线程进行简单的管理,并提供定时执行以及指定间隔循环执行等功能。

3.2.1.5、HandlerThread、IntentService理解

HandlerThread:

HandlerThread继承了Thread,它是一种可以使用HandlerThread,它的实现也很简单,就是在run方法中通过Looper.prepare()来创建消息队列,并通过Looper.loop()来开启消息循环,这样在实际的使用中就允许在HandlerThread中创建Handler了。普通的Thread主要用于在run方法中执行一个耗时任务,而HandlerThread在内部创建了消息队列,外界需要通过Handler的消息方式来通知HandlerThread执行一个具体的任务。HandlerThread是一个很有用的类,它在Android中的一个具体使用场景是IntentService。由于HandlerThreadrun方法是一个无限循环,因此当明确不需要再使用HandlerThread时,可以通过它的quit或者quitSafely方法来终止线程的执行。

  • IntentService源码分析
  • Android面试题-Service是否在main thread中执行, service里面是否能执行耗时的操作?

IntentService:

是一个特殊的Service,它继承了Service并且它是一个抽象类,因此必须创建它的子类才能使用IntentServiceIntentService可用于执行后台耗时的任务,当任务执行后它会自动停止,同时由于IntentService是服务的原因,这导致它的优先级比单纯的线程要高很多,所以IntentService比较适合执行一些高优先级的后台任务,因为它优先级高不容易被系统杀死。在实现上,IntentService封装了HandlerThreadHandler。IntentServiceonHandlerIntent方法是一个抽象方法,它需要我们在子类中实现,它的作用是从Intent参数中区分具体的任务并执行这些任务。

3.2.1.7、int、Integer有什么区别

主要考值传递和引用传递问题

int和Integer的区别

int和Integer的基本区别:

  1. int是基本数据类型,Integer是int包装类。
  2. Integer变量必须实例化后才能使用,int可以直接使用
  3. Integer的默认值是null,int默认值是0
  4. Integer变量实际上是对象的引用,指向new的Integer对象,int是直接存储数据

如何把ip地址存储在一个int 变量里面?

一个int占多少个字节?

Java语言中一个字符占几个字节?

3.2.1.8、手写生产者/消费者 模式

【Java】生产者消费者模式的实现

手写一个生产者/消费者模式(三种方式实现)

生产者/消费者实现原理:Java并发编程:线程间协作的两种方式:wait、notify、notifyAll和Condition

3.2.1.9、RecyclerView

看完这篇,面试RecyclerView的时候再也不怕了

android面试题(30)-RecycleView和ListView

面试常考点之RecyclerView回收和复用机制最全分析

Android自定义控件进阶篇,自定义LayoutManager

3.2.2、Android

3.2.2.1、android启动模式

需要了解下Activity栈和taskAffinity

  1. 1.Standard:系统默认,启动一个就多一个Activity实例
  2. 2.SingleTop:栈顶复用,如果处于栈顶,则生命周期不走onCreate()和onStart()去重新创建一个新的activity实例,会调用onNewIntent()复用位于栈顶的activity实例对象。如果不位于栈顶仍旧会重新创建activity的实例对象。适合推送消息详情页,比如新闻推送详情Activity;
  3. 3.SingleTask:设置了singleTask启动模式的activity在启动时,如果位于activity栈中,就会复用该activity,这样的话,在该实例之上的所有activity都依次进行出栈操作,即执行对应的onDestroy()方法,直到当前要启动的activity位于栈顶。一般应用在网页的图集,一键退出当前的应用程序,app首页。
  4. 4.SingleInstance:这个是SingleTask加强本,如果使用singleInstance启动模式的activity在启动的时候会复用已经存在的activity实例。不管这个activity的实例是位于哪一个应用当中,都会共享已经启动的activity的实例对象。使用了singlestance的启动模式的activity会单独的开启一个共享栈,这个栈中只存在当前的activity实例对象,适用新开Activity和app能独立开的,如系统闹钟。SingleTask和SingleInstance好像会影响到onActivityResult的回调,具体问题大家搜下,我就不详说。
  5. Intent也需要进一步了解,Action、Data、Category各自的用法和作用,还有常用的Intent.FLAG_ACTIVITY_SINGLE_TOP,Intent.FLAG_ACTIVITY_NEW_TASK,Intent.FLAG_ACTIVITY_CLEAR_TOP,等等,具体看下源码吧。

Activity的启动过程

插件化原理解析——Activity生命周期管理

3.2.2.2、View的绘制流程

ViewRoot

->performTraversal()->performMeasure()->performLayout()->perfromDraw()->View/ViewGroup measure()->View/ViewGroup onMeasure()->View/ViewGroup layout()->View/ViewGroup onLayout()->View/ViewGroup draw()->View/ViewGroup onDraw()

看下invalidate方法,有带4个参数的,和不带参数有什么区别;requestLayout触发measure和layout,如何实现局部重新测量,避免全局重新测量问题。

3.2.2.3、事件分发机制

->dispatchTouchEvent()->onInterceptTouchEvent()->onTouchEvent()requestDisallowInterceptTouchEvent(boolean)

还有onTouchEvent()、onTouchListener、onClickListener的先后顺序

3.2.2.4、消息分发机制

Handler机制

这个考得非常常见。一定要看源码,代码不多。带着几个问题去看:

1.为什么一个线程只有一个Looper、只有一个MessageQueue? 2.如何获取当前线程的Looper?是怎么实现的?(理解ThreadLocal) 3.是不是任何线程都可以实例化Handler?有没有什么约束条件? 4.Looper.loop是一个死循环,拿不到需要处理的Message就会阻塞,那在UI线程中为什么不会导致ANR? 5.Handler.sendMessageDelayed()怎么实现延迟的?结合Looper.loop()循环中,Message=messageQueue.next()和MessageQueue.enqueueMessage()分析。

3.2.2.5、AsyncTask源码分析

优劣性分析,这个网上一大堆,不重述。这两个问题我面试过程有3家公司问到。

Android Asynctask与Handler的比较,优缺点区别

首先从Android3.0开始,系统要求网络访问必须在子线程中进行,否则网络访问将会失败并抛出NetworkOnMainThreadException这个异常,这样做是为了避免主线程由于耗时操作所阻塞从而出现ANR现象。AsyncTask封装了线程池和Handler。AsyncTask有两个线程池:SerialExecutor和THREAD_POOL_EXECUTOR。前者是用于任务的排队,默认是串行的线程池:后者用于真正的执行任务。AsyncTask还有一个Handler,叫InternalHandler,用于将执行环境从线程池切换到主线程。AsyncTask内部就是通过InternalHandler来发送任务执行的进度以及执行结束等消息。

AsyncTask排队执行过程:系统先把参数Params封装为FutureTask对象,它相当于Runnable,接着FutureTask交给SerialExcutor的execute方法,它先把FutureTask插入到任务队列tasks中,如果这个时候没有正在活动的AsyncTask任务,那么就会执行下一个AsyncTask任务,同时当一个AsyncTask任务执行完毕之后,AsyncTask会继续执行其他任务直到所有任务都被执行为止。

关于线程池,AsyncTask对应的线程池ThreadPoolExecutor都是进程范围内共享的,都是static的,所以是AsyncTask控制着进程范围内所有的子类实例。由于这个限制的存在,当使用默认线程池时,如果线程数超过线程池的最大容量,线程池就会爆掉(3.0默认串行执行,不会出现这个问题)。针对这种情况。可以尝试自定义线程池,配合AsyncTask使用。

使用的优点:  简单快捷;过程可控

使用的缺点:  在使用多个异步操作和并需要进行Ui变更时,就变得复杂起来.

3.2.2.7、Binder机制,进程通信

Android跨进程通信:图文详解 Binder机制 原理

(1).transact和onTransact的区别

谈transact 和onTransact需要先聊聊iBinder

IBinder是什么呢?首先要明白,Android的远程调用(就是跨进程调用)就是通过IBinder实现的,下面是对android开发文档的翻译。

  IBinder是远程对象的基本接口,是为高性能而设计的轻量级远程调用机制的核心部分。但它不仅用于远程调用,也用于进程内调用。这个接口定义了与远程对象交互的协议。不要直接实现这个接口,而应该从Binder派生。

  IBinder的主要API是transact(),与它对应另一方法是Binder.onTransact()。第一个方法使你可以向远端的IBinder对象发送发出调用,第二个方法使你自己的远程对象能够响应接收到的调用。IBinder的API都是同步执行的,比如transact()直到对方的Binder.onTransact()方法调用完成后才返回。调用发生在进程内时无疑是这样的,而在进程间时,在IPC的帮助下,也是同样的效果。

  通过transact()发送的数据是Parcel,Parcel是一种一般的缓冲区,除了有数据外还带有一些描述它内容的元数据。元数据用于管理IBinder对象的引用,这样就能在缓冲区从一个进程移动到另一个进程时保存这些引用。这样就保证了当一个IBinder被写入到Parcel并发送到另一个进程中,如果另一个进程把同一个IBinder的引用回发到原来的进程,那么这个原来的进程就能接收到发出的那个IBinder的引用。这种机制使IBinder和Binder像唯一标志符那样在进程间管理。

  系统为每个进程维护一个存放交互线程的线程池。这些交互线程用于派送所有从另外进程发来的IPC调用。例如:当一个IPC从进程A发到进程B,A中那个发出调用的线程(这个应该不在线程池中)就阻塞在transact()中了。进程B中的交互线程池中的一个线程接收了这个调用,它调用Binder.onTransact(),完成后用一个Parcel来做为结果返回。然后进程A中的那个等待的线程在收到返回的Parcel后得以继续执行。实际上,另一个进程看起来就像是当前进程的一个线程,但不是当前进程创建的。

  Binder机制还支持进程间的递归调用。例如,进程A执行自己的IBinder的transact()调用进程B的Binder,而进程B在其Binder.onTransact()中又用transact()向进程A发起调用,那么进程A在等待它发出的调用返回的同时,还会用Binder.onTransact()响应进程B的transact()。总之Binder造成的结果就是让我们感觉到跨进程的调用与进程内的调用没什么区别。

  当操作远程对象时,你经常需要查看它们是否有效,有三种方法可以使用:

  1 transact()方法将在IBinder所在的进程不存在时抛出RemoteException异常。

  2 如果目标进程不存在,那么调用pingBinder()时返回false。

  3 可以用linkToDeath()方法向IBinder注册一个IBinder.DeathRecipient,在IBinder代表的进程退出时被调用。

  要实现IBinder来支持远程调用,应从Binder类派生一个类。Binder实现了IBinder接口。但是一般不需要直接实现此类,而是跟据你的需要由开发包中的工具生成,这个工具叫AIDL。你通过AIDL语言定义远程对象的方法,然后用AIDL工具生成Binder的派生类,然后就可使用之。然而,可是,但是,当然,你也可以直接从Binder类派生以实现自定义的RPC调用,或只是实例化一个原始的Binder对象直接作为进程间共享的令牌来使用。

以上出自:直接通过Binder的onTransact完成跨进程通信

Android用到的进程通信底层基本都是Binder,AIDL、Messager、广播、ContentProvider。不是很深入理解的,至少ADIL怎么用,Messager怎么用,可以写写看,另外序列化(Parcelable和Serilizable)需要做对比,这方面可以看看任玉刚大神的android艺术开发探索一书。

(2)binder底层实现?复制几次?  1次

binder一次跨进程通讯,只需要一次拷贝(原因后面会解析),而一般的像socket通讯则需要两次拷贝;

用户和内核空间分配了一段虚拟地址,这段虚拟地址将用于binder内存的访问。binder的物理内存页由binder驱动负责分配,然后这些物理页的访问,将分为进程的用户空间和进程内核空间。由于进程的用户空间和内核空间的虚拟地址范围是不一样的,所以这里分配的一段虚拟地址将包括进程的用户空间地址和内核空间地址
内核刚开始只是分配了一个物理页,并且分别将这个物理页映射到进程的内核虚拟地址空间V1(修改内核空间的页表映射)和进程的用户虚拟地址空间V2(修改用户空间的页表映射)。在用户空间访问V1和在内核空间访问V2,其实都是访问的是同一个物理内存块,从而实现进程的内核和用户空间共享同一块物理内存的目的。这样binder驱动在内核空间,将一段数据拷贝到这个物理页,则该进程的用户空间则不需要copy_to_user()即可以同步看到内核空间的修改,并能够访问这段物理内存.

腾讯面试题——谈一谈Binder的原理和实现一次拷贝的流程_动脑学院[David]的博客-CSDN博客_binder一次拷贝原理

Binder传输数据大小限制:Binder内存大小是不到1M的,准确说是 110241024) - (4096 *2)

(3)Android Binder有哪些特点
● 基于C/S模式, 每次IPC只需要一次数据拷贝
● 支持同步与异步两种调用方式
● 服务的线程池自动管理: 按需创建
● 接口基于AIDL(Android Interface Definition Language)来描述
● 支持多种类型基本数据的序列化与反序列化
● 可以通过进程的UID/PID来识别验证调用者的身份

3.2.2.8、动态权限适配问题、自定义权限、换肤实现原理

国产 Android 权限申请最佳适配方案 —— permissions4m

Rxpermissions

这方面看下鸿洋大神的博文吧

换肤实现原理 :

LayoutInflater.setFactory还非常适合一个场景,就是换肤,换肤需要解决的核心问题有两个:

  1. 外部资源的加载;可以通过构造AssetManager,反射调用其addAssetPath就可以完成。
  2. 定位到需要换肤的View;可以利用在onCreateView中,根据view的属性来定位,例如你可以让需要换肤的view添加一个自定义的属性skin_enabled=true(最开始有打印属性),并且利用一些手段拿到构造到的view,就能在View构造阶段定位的需要换肤的View。

3.2.2.9、Android 有哪些存储数据的方式

Android中的5种数据存储方式

  • 1 使用SharedPreferences存储数据;
  • 2 文件存储数据;
  • 3 SQLite数据库存储数据;
  • 4 使用ContentProvider存储数据;
  • 5 网络存储数据;

SharedPreference原理,能否跨进程?如何实现?

深入理解SharedPrefences实现原理

Android 面试(六):你已经用 SharedPrefrence 的 apply() 替换commit()

请不要滥用SharedPreference

3.3、性能优化问题

  1. 性能优化工具 (TraceView、Systrace、调试 GPU 过度绘制 & GPU 呈现模式分析、Hierarchy Viewer、MAT、Memory Monitor & Heap Viewer & Allocation Tracker 等)

    性能优化工具篇总结 - 简书

    Heap Viewer,Profiler

    MAT,LeakCanaray

    Layout Inspector,Lint

  2. 性能优化
    (1)网络:API 优化、流量优化、弱网优化
    (2)内存:OOM 处理、内存泄漏、内存检测、分析、Bitmap 优化
    (3)绘制
    (4)电量:WeakLock 机制、JobScheduler 机制
    (5)APK 瘦身:  Lint
    (6)内存抖动
    (7)内存泄漏
    (8)卡顿
    (9)性能优化:布局优化、过度渲染处理、ANR 处理、监控、埋点、Crash 上传。
  3. android 性能优化 -- 启动过程 冷启动 热启动

  4. Android内存管理-OnTrimMemory

3.3.1、UI优化

a.合理选择RelativeLayout、LinearLayout、FrameLayout,RelativeLayout会让子View调用2次onMeasure,而且布局相对复杂时,onMeasure相对比较复杂,效率比较低,LinearLayout在weight>0时也会让子View调用2次onMeasure。LinearLayout weight测量分配原则。

b.使用标签

c.减少布局层级,可以通过手机开发者选项>GPU过渡绘制查看,一般层级控制在4层以内,超过5层时需要考虑是否重新排版布局。

d.自定义View时,重写onDraw()方法,不要在该方法中新建对象,否则容易触发GC,导致性能下降

e.使用ListView时需要复用contentView,并使用Holder减少findViewById加载View。

f.去除不必要背景,getWindow().setBackgroundDrawable(null)

g.使用TextView的leftDrawabel/rightDrawable代替ImageView+TextView布局

3.3.2、内存优化

主要为了避免OOM和频繁触发到GC导致性能下降

a.Bitmap.recycle(),Cursor.close,inputStream.close()

b.大量加载Bitmap时,根据View大小加载Bitmap,合理选择inSampleSize,RGB_565编码方式;使用LruCache缓存

c.使用 静态内部类+WeakReference 代替内部类,如Handler、线程、AsyncTask

d.使用线程池管理线程,避免线程的新建

e.使用单例持有Context,需要记得释放,或者使用全局上下文

f.静态集合对象注意释放

g.属性动画造成内存泄露

h.使用webView,在Activity.onDestory需要移除和销毁,webView.removeAllViews()和webView.destory()

Webview内存泄露优化

备:使用LeakCanary检测内存泄露

Android:你要的WebView与 JS 交互方式 都在这里了

3.2.3、响应速度优化

Activity如果5秒之内无法响应屏幕触碰事件和键盘输入事件,就会出现ANR,而BroadcastReceiver如果10秒之内还未执行操作也会出现ANR,Serve20秒会出现ANR 为了避免ANR,可以开启子线程执行耗时操作,但是子线程不能更新UI,因此需要Handler消息机制、AsyncTask、IntentService进行线程通信。

备:出现ANR时,adb pull data/anr/tarces.txt 结合log分析

ANR问题:

1、ANR排错一般有三种类型

  1. KeyDispatchTimeout(5 seconds) --主要是类型按键或触摸事件在特定时间内无响应
  2. BroadcastTimeout(10 seconds) --BroadcastReceiver在特定时间内无法处理完成
  3. ServiceTimeout(20 secends) --小概率事件 Service在特定的时间内无法处理完成

2、哪些操作会导致ANR 在主线程执行以下操作:

  1. 高耗时的操作,如图像变换
  2. 磁盘读写,数据库读写操作
  3. 大量的创建新对象

3、如何避免

  1. UI线程尽量只做跟UI相关的工作
  2. 耗时的操作(比如数据库操作,I/O,连接网络或者别的有可能阻塞UI线程的操作)把它放在单独的线程处理
  3. 尽量用Handler来处理UIThread和别的Thread之间的交互

4、解决的逻辑

  1. 使用AsyncTask

    1. 在doInBackground()方法中执行耗时操作
    2. 在onPostExecuted()更新UI
  2. 使用Handler实现异步任务
    1. 在子线程中处理耗时操作
    2. 处理完成之后,通过handler.sendMessage()传递处理结果
    3. 在handler的handleMessage()方法中更新UI
    4. 或者使用handler.post()方法将消息放到Looper中

5、如何排查

  1. 首先分析log
  2. 从trace.txt文件查看调用stack,adb pull data/anr/traces.txt ./mytraces.txt
  3. 看代码
  4. 仔细查看ANR的成因(iowait?block?memoryleak?)

6、监测ANR的Watchdog

最近出来一个叫LeakCanary

#FC(Force Close) ##什么时候会出现

  1. Error
  2. OOM,内存溢出
  3. StackOverFlowError
  4. Runtime,比如说空指针异常

##解决的办法

  1. 注意内存的使用和管理
  2. 使用Thread.UncaughtExceptionHandler接口

3.2.4、其他性能优化

a.常量使用static final修饰 b.使用SparseArray代替HashMap c.使用线程池管理线程 d.ArrayList遍历使用常规for循环,LinkedList使用foreach e.不要过度使用枚举,枚举占用内存空间比整型大 f.字符串的拼接优先考虑StringBuilder和StringBuffer g.数据库存储是采用批量插入+事务

android面试(16)-数据库存储框架greendao

深入理解Java中的String(大坑)_String,java

3.2.4.2:String全面解析

不是特别需要请不要使用new关键字创建字符串

从前文我们知道使用new关键字创建String的时候,即便串池中存在相同String,仍然会再次在堆内存中创建对象,会浪费内存,另一方面对象的创建相较于从串池中取效率也更低下。

String StringBuffer StringBuilder的区别:

关于三者的区别,在面试题中经常的出现,String对象不可变,因此在进行任何内容上的修改时都会创建新的字符串对象,一旦修改操作太多就会造成大量的资源浪费。

StringBuffer和StringBuilder在进行字符串拼接的时候不会创建新的对象,而是在原对象上修改,不同之处在于StringBuffer线程安全,StringBuilder线程不安全。所以在进行字符串拼接的时候推荐使用StringBuffer或者StringBuilder。

3.3、设计模式

1.单例模式:好几种写法,要求会手写,分析优劣。一般双重校验锁中用到volatile,需要分析volatile的原理

2.观察者模式:要求会手写,有些面试官会问你在项目中用到了吗?实在没有到的可以讲一讲EventBus,它用到的就是观察者模式

3.适配器模式:要求会手写,有些公司会问和装饰器模式、代理模式有什么区别?

1).适配器模式:

2).代理模式和装饰模式有点像,都是持有了被代理或者被装饰对象的引用。它们两个最大的不同就是装饰模式对引用的对象增加了功能,而代理模式只是对引用对象进行了控制却没有对引用对象本身增加功能。

4.建造者模式+工厂模式:要求会手写

5.策略模式:这个问得比较少,不过有些做电商的会问。

6.MVC、MVP、MVVM:比较异同,选择一种你拿手的着重讲就行

MVC、MVP、MVVM

Android架构组件(三)——ViewModel

Android DataBinding原理解析

3.4、数据结构

1.HashMap、LinkedHashMap、ConcurrentHashMap,在用法和原理上有什么差异,很多公司会考HashMap原理,通过它做一些扩展,比如中国13亿人口年龄的排序问题,年龄对应桶的个数,年龄相同和hash相同问题类似。

2.ArrayList和LinkedList对比,这个相对简单一点

ArrayList和linkedList的区别

共性:ArrayList与LinkedList都是List接口的实现类,因此都实现了List的所有未实现的方法,只是实现的方式有所不同。

区别:List接口的实现方式不同

1.ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构。

2.对于随机访问get和set,ArrayList觉得优于LinkedList,因为LinkedList要移动指针。

3.对于新增和删除操作add和remove,LinedList比较占优势,因为ArrayList要移动数据。

ArrayList实现了List接口,以数组的方式来实现的,因此对于快速的随机取得对象的需求,使用ArrayList实现执行效率上会比较好。LinkedList是采用链表的方式来实现List接口的,因此在进行insert和remove动作时效率要比ArrayList高。适合用来实现Stack(堆栈)与Queue(队列)

3.5、源码理解

项目中多多少少会用到开源框架,很多公司都喜欢问原理和是否看过源码,比如网络框架Okhttp,这是最常用的,现在Retrofit+RxJava也很流行。EventBus

3.5.1、网络框架库 Okhttp

okhttp源码一定要去看下,里面几个关键的类要记住,还有连接池,拦截器都需要理解。被问到如何给某些特定域名的url增加header,如果是自己封装的代码,可以在封装Request中可以解决,也可以增加拦截器,通过拦截器去做。

推荐一篇讲解Okhttp不错的文章

3.5.2、消息通知 EventBus

EventBus 源码和设计之禅

1.EventBus原理:建议看下源码,不多。内部实现:观察者模式+注解+反射

2.EventBus可否跨进程问题?代替EventBus的方法(RxBus)

3.5.3、图片加载库(Fresco、Glide、Picasso)

1.项目中选择了哪个图片加载库?为什么选择它?其他库不好吗?这几个库的区别

2.项目中选择图片库它的原理,如Glide(LruCache结合弱引用),那么面试官会问LruCache原理,进而问LinkedHashMap原理,这样一层一层地问,所以建议看到不懂的追进去看。如Fresco是用来MVC设计模式,5.0以下是用了共享内存,那共享内存怎么用?Fresco怎么实现圆角?Fresco怎么配置缓存?

Android图片加载框架最全解析(三),深入探究Glide的缓存机制

Android图片加载框架最全解析(五),Glide强大的图片变换功能

3.5.4、消息推送Push

1.项目中消息推送是自己做的还是用了第三方?如极光。还有没有用过其他的?这几家有什么优势区别,基于什么原因选择它的?

2.消息推送原理是什么?如何实现心跳连接?

3.5.7、热更新、热修复、插件化(这一块要求高点,一般高级工程师是需要理解的)

了解classLoader

3.6、新技术

RxJava、RxBus、RxAndroid,这个在面试想去的公司时,可以反编译下他们的包,看下是不是用到,如果用到了,面试过程难免会问道,如果没有,也可以忽略,但学习心强的同学可以看下,比较是比较火的框架。

Retrofit,熟练okhttp的同学建议看下,听说结合RxJava很爽。

Kotlin

3.7、算法

· 排序算法有哪些?

· 最快的排序算法是哪个?

· 手写一个冒泡排序

· 手写快速排序代码

· 快速排序的过程、时间复杂度、空间复杂度

· 手写堆排序

· 堆排序过程、时间复杂度及空间复杂度

· 写出你所知道的排序算法及时空复杂度,稳定性

· 二叉树给出根节点和目标节点,找出从根节点到目标节点的路径

· 给阿里2万多名员工按年龄排序应该选择哪个算法?

· GC算法(各种算法的优缺点以及应用场景)

· 蚁群算法与蒙特卡洛算法

· 子串包含问题(KMP 算法)写代码实现

· 一个无序,不重复数组,输出N个元素,使得N个元素的和相加为M,给出时间复杂度、空间复杂度。手写算法

· 万亿级别的两个URL文件A和B,如何求出A和B的差集C(提示:Bit映射->hash分组->多文件读写效率->磁盘寻址以及应用层面对寻址的优化)

· 百度POI中如何试下查找最近的商家功能(提示:坐标镜像+R树)。

· 两个不重复的数组集合中,求共同的元素。

· 两个不重复的数组集合中,这两个集合都是海量数据,内存中放不下,怎么求共同的元素?

· 一个文件中有100万个整数,由空格分开,在程序中判断用户输入的整数是否在此文件中。说出最优的方法

· 一张Bitmap所占内存以及内存占用的计算

· 2000万个整数,找出第五十大的数字?

· 烧一根不均匀的绳,从头烧到尾总共需要1个小时。现在有若干条材质相同的绳子,问如何用烧绳的方法来计时一个小时十五分钟呢?

· 求1000以内的水仙花数以及40亿以内的水仙花数

· 5枚硬币,2正3反如何划分为两堆然后通过翻转让两堆中正面向上的硬8币和反面向上的硬币个数相同

· 时针走一圈,时针分针重合几次

· N*N的方格纸,里面有多少个正方形

· x个苹果,一天只能吃一个、两个、或者三个,问多少天可以吃完?

【算法】DFS考察

1、一个二维数组,数组中的内容非0即1,0代表海洋,1代表陆地,求所给二维数组代表的区域中陆地面积的最大值。

答案:leetcode刷题(63)——岛屿类问题通用解法

【算法】二叉树中序遍历(字节跳动-抖音-一面)

void InOrderTraverse2(BiTree biTree) {if (biTree == NULL) {cout << "该树为空,无法遍历!" << endl;}stack<BiNode *> stack1;BiNode *biNode = biTree;while (biNode != NULL || !stack1.empty()) {if (biNode != NULL) {stack1.push(biNode);biNode = biNode->lchild;} else {biNode = stack1.top();stack1.pop();cout << biNode->data << " ";biNode = biNode->rchild;}}
}

【算法】判断平衡二叉树(字节跳动-抖音-二面)

递归求解或者层次遍历求解。

答案:笔试面试算法经典--判断二叉树是否是平衡二叉树(Java)

【手写算法】二叉树,给出根节点和目标节点,找出从根节点到目标节点的路径

红黑树之 Java的实现

二叉树的遍历(前序、中序、后序、已知前中序求后序、已知中后序求前序)

Android面试大总结相关推荐

  1. 【Android 面试基础知识点整理】

    针对Android面试中常见的一些知识点整理,Max 仅仅是个搬运工.感谢本文中引用文章的各位作者,给大家分享了这么多优秀文章.对于当中的解析,是原作者个人见解,有错误和不准确的地方,也请大家积极指正 ...

  2. 我的android面试经历

    做了一年的android应用开发,准备换个工作环境,结果在面试中却成了一个典型的面霸,两周的十个工作日里,竟然笔试加面试达到了15次.不过,在这些面试中学到了不少东西!下面把我的android面试经历 ...

  3. Android面试:Java相关

    Android面试常见Java相关问题. 原文链接:http://www.nowcoder.com/discuss/3244 Switch能否用string做参数? 在 Java 7 之前, swit ...

  4. BAT Android面试专题深入探究:四大组件+ViewPager+组件化架构+Bitmap

    本篇是结合我之前面试别人的经验,以及跟一些在BAT上班的朋友,讨论总结出的一份很深的大公司需要用到的一些高端Android技术.这里也专门整理了一个文档,重点和难点都有详细解析.这些题目有点技术含量, ...

  5. Android端发送字符到Wed端,Android面试-socket和websocket

    Android与服务器的通信方式主要有两种,一是Http通信,一是Socket通信.两者的最大差异在于,http连接使用的是"请求-响应方式",即在请求时建立连接通道,当客户端向服 ...

  6. 看完99%的人都学会了!9次Android面试经验总结,我先收藏为敬

    我们都是被圈养的人? 我的朋友程序员K,说他在电力行业的一家软件公司做了八年Android开发,用到的各种技术,数据库,网络请求,事件传递,响应框架都很熟悉,甚至JNI/NDK/Framework,J ...

  7. 我想谈谈关于Android面试那些事,一篇文章帮你解答

    开头 通常作为一个Android APP开发者,我们并不关心Android的源代码实现,不过随着Android开发者越来越多,企业在筛选Android程序员时越来越看中一个程序员对于Android底层 ...

  8. 最新BAT大厂面试者整理的Android面试题目模板,成功入职字节跳动

    前言 **一年中第一段跳槽高潮就要来了,**看到同事一个个离职,又有一部分同事已经找到满意的工作,于是自己也盲目的开始面试起来(期间也没有准备充分),日夜奔走,简历投了很多家公司,然后就是一连串的面试 ...

  9. 普通二本的辛酸Android面试之路,算法太TM重要了

    前言 编程是一个江湖,江湖之大,鱼龙混杂,一部分江湖人士乃虾兵蟹将,一不小心就被一箭射死,我们称之为"码农",这些人事江湖的重要组成部分,他们承担着堆砌代码,实现功能设计的使命,他 ...

最新文章

  1. <X86汇编语言:实模式到保护模式>四十四 协同式任务切换
  2. 每个软件工程师都应该尝试的5件事
  3. linux 安装vbox增强工具
  4. Java常考面试题(一)
  5. Mr.J-- HTTP学习笔记(九)-- Web机器人
  6. QT5开发及实例学习之三字符串类
  7. enityframework 已连接的当前状态为打开。_蓝牙连接有问题吗?尝试针对macOS的以下6个修复程序
  8. 2020年百度之星程序设计大赛-初赛二(Poker、Distance)
  9. 惠普z800工作站bios设置_惠普台式机装win10系统及bios设置(uefi+gpt)
  10. 硬核图解面试最怕的红黑树【建议反复摩擦】
  11. 【Other】千字文 硬笔 楷书 字帖
  12. 继电器在交流应用时的zero-crossing
  13. 13.荔枝派 zero(全志V3S)-gadget Mass Storage虚拟U盘
  14. redis通过key模糊搜索_jedis模糊查询key
  15. Linux环境使用授权码实现软件授权
  16. #includecstring
  17. 什么是硬件加密与软件加密,有什么区别?
  18. Qt纯代码实现菜单栏、工具栏、状态栏
  19. PermissionError: [WinError 32] 另一个程序正在使用此文件,进程无法访问
  20. 网络云存储技术Windows server 2012 (项目十一 NAS服务器磁盘配额的配置与管理)

热门文章

  1. javaweb课程设计(简单的学生成绩查询系统)
  2. 区块链入门必读(FISCO)
  3. 光伏等战略性新兴产业成为中国经济蓄势前行的新动力
  4. C语言双感叹号作用!!
  5. Sivers Semiconductors 与 Richardson RFPD 签署全球分销协议
  6. 配音App平台开发要有的功能
  7. 接上篇(解决float导致塌陷问题)之clear:both失效
  8. java前端用什么软件好_Java开发者必备的六款工具
  9. C语言 编程判断花瓶是谁打碎的,【数组编程面试题】面试问题:C语言解决是谁… - 看准网...
  10. 银行卡I类II类III类账户区别