Android面试知识

201 阅读13分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

@toc

参考文章

  1. 备战2022,Android中高级面试必知必会
  2. 《Android 源码设计模式解析与实战 第2版》

2 assets和res/raw的区别

  1. assets中的文件资源不会映射到R中,而res中的文件都会映射到R中,所以raw文件夹下的资源都有对应的ID;
  2. assets可以能有更深的目录结构,而res/raw里面只能有一层目录;
  3. 资源存取方式不同,assets中利用AssetsManager,而res/raw直接利用getResource(), openRawResource(R.raw.fileName)

3 Serializable 和 Parcelable 的区别

  1. Serializable 使用 I/O 读写存储在硬盘上,而 Parcelable 是直接在内存中读写。很明显,内存的读写==速度==通常大于 IO读写,所以在 Android 中传递数据优先选择 Parcelable。
  2. Serializable 会使用反射,序列化和反序列化过程需要大量 I/O 操作; Parcelable 自已实现封送和解封(marshalled &unmarshalled)操作不需要用反射,数据也存放在Native内存中,==效率==要快很多。

传递大数据的方式

文件,数据库,静态变量

Context的理解

是运行上下文环境。代码角度看是Application、Activity、Service。 所有Context都是在主线程ActivityThread创建

导致内存泄露: 2 1. 静态资源 2. 单例模式 避免:

  1. 尽量少用Context对象获取静态变量,静态方法,以及单例对象
  2. 在引用静态资源,创建静态方法,单例等情况下,使用生命周期更长的Application的Context去创建UI相关的对象,如Dialog,View等。

Activity

Activity与Fragment

  1. Activity、View、Window的关系?

    Activity -》 PhoneWindow -》DecorView -》 ActionBar&ContentView DecorView是一个FrameLayout

  2. Activity1跳转到Activity2,Activity2显示缓慢的原因?

    • 在Activity1的onPause()有耗时操作;
    • 在Activity2的onCreate()或者onStart()onResume()中有耗时操作; 总结 在Activity2的onResume及之前有耗时操作(以上的4个方法过程,均在Activity2的onResume()之前执行)

4 Service

  1. startService和 bindService的区别
    • startService: 与调用者无关, 调用者退出, service不会关闭; 生命周期:onCreate-onStartCommand -- onDestroy
    • bindService: 与调用者绑定, 调用者关闭, service会关闭 (activity在finish的时候, 会直接调用service进入销毁周期); 生命周期:onCreate-onBind -- onUnbind-onDestroy
  2. IntentService
    • IntentService继承自Service,可用 startService() 启动,也需要在 AndroidManifest.xml 中注册
    • 可多次启动同一个IntentService,它们会自一个接一个地排队处理
    • 可以执行耗时任务, 在onHandleIntent()中执行
    • 操作完成时,不用手动停止IntentService,它会自动判定停止, 多次startService, 只会执行一次onDestroy

* Handler机制

Handler发送Message到MessageQueue中, Looper从MessageQueue中取出Message,交给Handler的handleMessage方法进行处理

Handler:负责消息的发送和处理 Message:消息对象(类似于链表的一个节点) MessageQueue:消息队列,用于存放消息对象的数据结构 Looper:消息队列的矗立着,用于轮询消息队列的消息对象

5.1 子线程能否直接new一个Handler?

不能直接new,因为在Handler的构造方法中,会通过Looper.myLooper()获取mLooper对象,子线程中mLooper对象为空,会抛异常。 如果是创建子线程的Handler, 需要三步: 1. Looper.prepare(); //为当前线程准备消息队列 2. Handler handler = new Handler(); // 默认构造方法跟当前线程中的Looper产生关联 3. Looper.loop(); //开启循环取消息 因为子线程的handler需要准备looper,同时要启动Looper.loop(),只有这样handler的机制才能够正常运行。

5.2 一个线程可以有几个Handler,几个Looper,几个MessageQueue对象?

无数个Handler,一个Looper,一个MessageQueue

在Looper.prepare()中,创建了Looper对象,并放入ThreadLocal中,通过ThreadLocal获取Looper对象,ThreadLocal内部维护了一个ThreadLocalMap,其是以当前thread作为key的,所以可以看出一个thread最多只有一个looper对象;在Looper的构造方法中,会创建MessageQueue对象,因为Looper只会构造一个,所以MessageQueue对象只有一个。

5.3 Handler怎么与Looper绑定的?

5.4 为什么用ThreadLocal保存Looper?

每个Thread内部都有一个ThreadLocalMap对象,用来存储Looper。这样,每个线程在存储Looper对象到ThreadLocal中的时候,其实是存储在每个线程内部的ThreadLocalMap对象中,从而其他线程无法获取到Looper对象,实现线程隔离

5.5 主线程的Looper.loop()的死循环为什么不会造成ANR?

5.6 子线程能否更新UI

5.7 多个Handler往MessageQueue中添加数据,怎么保证线程安全的?

锁 enqueueMessage方法中有个Synchronized(this),使用的是同一个MessageQueue的时候,其中所有的方法代码等都会受限。

5.8 主线程的死循环一直运行是不是特别消耗CPU资源呢?

不会,这里就涉及到Linux pipe/epoll机制,简单说就是在==主线程的MessageQueue没有消息时,便阻塞==在loop的queue.next()中的nativePollOnce()方法里,==此时主线程会释放CPU资源进入休眠状态,直到下个消息到达或者有事务发生==,通过往pipe管道写端写入数据来==唤醒主线程工作==。这里采用的epoll机制,是一种IO多路复用机制,可以同时监控多个描述符,当某个描述符就绪(读或写就绪),则立刻通知相应程序进行读或写操作,本质同步I/O,即读写是阻塞的。 所以说,==主线程大多数时候都是处于休眠状态,并不会消耗大量CPU资源==

线程

  1. Thread的构造参数有哪些,是什么意思?
  2. Runnable和Thread有什么关系?
  3. Runnable和Callable有什么区别?

线程池

问题

  1. 线程池的构造方法的参数的含义?
  2. java内置了哪些线程池?
  3. 内置的线程池都有哪些局限?

6 网络

6.1 http与https?

博客园=》HTTP与HTTPS的区别

  • HTTP:是互联网上应用最为广泛的一种网络协议,是一个客户端和服务器端请求和应答的标准(TCP),==用于从WWW服务器传输超文本到本地浏览器的传输协议==,它可以使浏览器更加高效,使网络传输减少。
  • HTTPS:是以安全为目标的HTTP通道,简单讲是HTTP的安全版,即==HTTP下加入SSL层==,HTTPS的安全基础是SSL,因此加密的详细内容就需要SSL。

HTTPS协议的主要作用

  1. 建立一个信息安全通道,来保证数据传输的安全;
  2. 确认网站的真实性。

HTTPS和HTTP的区别主要如下:

  1. https协议需要到ca申请证书,一般免费证书较少,因而需要一定费用。
  2. http是超文本传输协议,信息是明文传输,https则是具有安全性的ssl加密传输协议。
  3. http和https使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。
  4. http的连接很简单,是无状态的;HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,比http协议安全。

客户端在使用HTTPS方式与Web服务器通信时有以下几个步骤

  1. 客户使用https的URL访问Web服务器,要求与Web服务器建立SSL连接。
  2. Web服务器收到客户端请求后,会将网站的证书信息(证书中包含公钥)传送一份给客户端。
  3. 客户端的浏览器与Web服务器开始协商SSL连接的安全等级,也就是信息加密的等级。
  4. 客户端的浏览器根据双方同意的安全等级,建立会话密钥,然后利用网站的公钥将会话密钥加密,并传送给网站。
  5. Web服务器利用自己的私钥解密出会话密钥。
  6. Web服务器利用会话密钥加密与客户端之间的通信 在这里插入图片描述

https加密过程

https加密过程

TCP & UDP

Bilibili=》一条视频讲清楚TCP协议与UDP协议-什么是三次握手与四次挥手

不同的硬件、操作系统之间的通信,所有的这一切都需要一种规则。而我们就把这种规则称为==协议==(protocol) TCP/IP 是互联网相关的各类协议族的总称,比如:TCP,UDP,IP,FTP,HTTP,ICMP,SMTP 等都属于 TCP/IP 族内的协议。这些协议可以划分为四层,分别为链路层、网络层、传输层和应用层

-UDPTCP
是否连接无连接面向连接
是否可靠不可靠传输,不使用流量控制和拥塞控制可靠传输,使用流量控制和拥塞控制
连接对象个数支持一对一,一对多,多对一和多对多交互通信只能是一对一通信
传输方式面向报文面向字节流
首部开销首部开销小,仅8字节首部最小20字节,最大60字节
适用场景适用于实时应用(IP电话、视频会议、直播等)适用于要求可靠传输的应用,例如文件传输

TCP连接的三次握手是什么?

  1. 客户端向服务器发送SYN同步报文段,请求建立连接;
  2. 服务器确认收到客户端的连接请求,并向客户端发送SYN同步报文,表示要向客户端建立连接;
  3. 客户端收到服务器的确认请求后,处于建立连接状态,向服务器发送确认报文。 在这里插入图片描述

总结 客户端是在收到确认请求后,先建立连接; 服务器收在收到客户端的确认后,建立连接; 发起连接请求的一定是客户端。

为什么要三次握手? 为了解决网络信道不可靠的问题。如第一次发送的请求因为某些原因没有送达给服务端,此时客户端重新发送,若阻塞忽然解除,服务端会接收到两个消息,出现不可靠的问题。

TCP断开连接时的四次挥手是什么?

  1. 客户端发送FIN,主动断开连接;(客户端请求断开连接)
  2. 服务器收到客户端的FIN,发送ACK进行回执;(服务端准备断开连接)
  3. 服务器准备好断开连接的工作后,发送FIN断开连接;(服务端断开连接)
  4. 客户端接收服务端的FIN,发送ACK,进入超时等待状态(防止服务端未收到ACK包),断开连接 。(客户端断开连接完毕) 在这里插入图片描述

Socket

* OkHttp的原理

双任务队列机制

* Retrofit原理

7 View的绘制

  1. 绘制流程?
  2. view是怎么添加到窗口上的?

IPC(进程间通信)和Binder机制

进程间通信机制;也是一个驱动; 用户空间相互隔离,内核空间共享。

多进程的优点: 内存增加(每一个进程的内存额定) 风险隔离(每一个进程,是一个单独的app)

应用多进程的举例:

  1. webView;视频播放;音乐;大图浏览;推送...

· | Binder|共享内存|Socket

  • | -| - |- 性能 | 拷贝一次|无需拷贝 | 拷贝两次 安全性 | 为每个App分配UID,同时支持实名和匿名|依赖上层协议,访问接入点是开放的,不安全|同左 特点|基于C/S架构,易用性高|控制复杂,易用性差|基于C/S架构,作为一款通用接口,传输效率低,开销大

实名:如可以通过getSystemService()获取 匿名:如自己创建的Service,别的app取不到

性能:共享内存()>Binder>其他IPC(如Socket等) 安全性:Binder>共享内存≈Socket

MMAP (内存映射)

  • 让虚拟内存和物理内存直接联系
  • Linux通过将一个虚拟内存区域与一个磁盘上的对象关联起来,以初始化这个虚拟内存区域的内容,这个过程成为内存映射(memory-mapping);
  • 对文件进行mmap,会在进程的虚拟内存分配地址空间,创建映射关系;
  • 实现这样的映射关系后,就可以采用指针的方式读写操作这一段内存,而系统会自动回写到对应的文件磁盘上。
  • 扩展: 用户不能直接操作磁盘文件,要通过mmap映射
  1. 为什么使用binder机制通信?

    性能:数据只复制一次 mmap; 安全:内核驱动pid

* 设计模式

我的=>《设计模式》 设计模式是对面向对象的实现

博客园=>《Android涉及到的设计模式》 SOLID 单一职责原则;开闭原则;里式替换原则;依赖倒置原则

Android中常用的设计模式?并源码举例?

  1. 单例模式
  2. 代理模式

10 App优化

10.1 内存溢出OOM

  • 常见的OOM的原因
    1. bitmap过大
    2. 文件流没有关闭
    3. 数据库没有关闭

10.2 内存泄露

  • 常见的内存泄露的原因
    1. Service执行完没有停止操作或者停止失败;
    2. 非静态内部类导致的内存泄漏,如handler

10.3 启动速度的优化

图片相关

  1. 加载大图的处理

Glide原理

* Kotlin协程

* JetPack

MVVM

AMS(ActivityManagerService)

  1. 如何理解startActivity启动流程

WMS

* 混合开发之H5与原生交互

CSDN =》 Android混合编程:WebView实践

WebView wv = (WebView) findViewById(R.id.wv);
//获取webSettings
WebSettings settings = wv.getSettings();
//让webView支持JS
settings.setJavaScriptEnabled(true);
//加载百度网页
wv.loadUrl("http://www.baidu.com/");
//加载本地的静态网页
wv.loadUrl("file:///android_asset/123.html"); 	//assets目录下
wv.loadUrl("file:///sdcard/");	//sd卡
//这个方法用于让H5调用android方法
wv.addJavascriptInterface(this, "android");	//第一个参数把自身传给js 第二个参数是this的一个名字

在android调用js函数:

wv.loadUrl("javascript:message()");	//无参函数
wv.loadUrl("javascript:message2('" + name + "')");	//有参函数的参数要加单引号

网页调Android方法:

//这个注解必须加 因为 兼容问题
@JavascriptInterface
public void setMessage(String name) {
  Toast.makeText(this, "我弹弹" + name, Toast.LENGTH_SHORT).show();
}

Java知识

1. new一个对象的过程?

类加载 -> 检查加载 ->(失败则重新执行类加载) -> 分配内存 -> 内存空间初始化 -> 设置 -> 对象初始化

2. wait()、notify()和sleep()

  1. 都必须在synchronized语句块中使用
  2. wait()是强迫一个线程等待;notify()是通知一个线程继续运行
  3. wait()和sleep()都可以暂停当前线程,区别在于wait会同时释放对象锁

3. HashMap的原理

史上最详细的 JDK 1.8 HashMap 源码解析

jdk1.7 数组+链表 jdk1.8 数组+链表+红黑树

4. synchronized

  • 在多线程环境下,用来作为线程安全的同步锁
  • 内置锁,锁的开关由jvm控制

用法 所有对象有一个锁旗标,默认为1,在进入到synchronized修饰的代码块之前,会判断锁旗标是否为1,为1则进入,方法执行完毕之后,锁旗标置变成0

  1. 修饰代码块 修饰的是某个具体对象 synchronized(object) { }
  2. 修饰成员方法 修饰的是this public sychronized void func() { }
  3. 修饰静态方法 修饰的是Class对象 public sychronized static void func() { }

5. 深拷贝和浅拷贝

6. (略)死锁

定义: 指==多个进程在运行过程中因争夺资源而造成的一种僵局==,当进程处于这种僵持状态时,若无外力作用,它们都将无法再向前推进。 因此我们举个例子来描述,如果此时有一个线程A,按照先锁a再获得锁b的的顺序获得锁,而在此同时又有另外一个线程B,按照先锁b再锁a的顺序获得锁。

CSDN=> 《死锁面试题》