欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 文旅 > 文化 > 2024年Android面试总结

2024年Android面试总结

2024/11/30 4:29:47 来源:https://blog.csdn.net/u012556114/article/details/144016026  浏览:    关键词:2024年Android面试总结

2024年Android面试总结

1.动画类型有哪些?插值器原理?

答:1. 帧动画(Frame Animation)

  • 特点:通过连续播放一系列图像帧来创建动画效果。
  • 原理:使用AnimationDrawable类加载XML定义的帧图片,通过定时更新当前显示的帧来实现动画。
  • 使用场景:适合简单的动画效果,如GIF动画。

2. 补间动画(Tween Animation)/ 视图动画(View Animation)

  • 子类型:平移(Translate)、旋转(Rotate)、缩放(Scale)、透明度(Alpha)。
  • 特点:通过指定动画开始和结束的属性值,系统自动计算变化过程。
  • 原理:基于View的动画,通过修改Canvas的绘制矩阵来实现动画效果,但不改变View的实际属性。
  • 使用场景:适合简单的视图动画效果,如页面切换时的淡入淡出。
  • 底层解析
  1. AnimationUtils.loadAnimation()开始加载解析,通过xmlParse解析相应字段节点根据不同动画类型创建动画;
  2. View.startAnimation(xxx)触发invalidate()重绘,draw()根据动画标志位计算得到animation,并更新transformation,触发下一次绘制;
  3. 结果返回给View在绘制时对画布Canvas做矩阵变换从而实现动画。
  4. 这是在draw层面实现,只有视觉变化,实际属性不变。

3. 属性动画(Property Animation)

  • 特点:通过动态修改对象的属性值来实现动画效果,功能强大且灵活。
  • 原理:执行animator.start()后,动画作为回调注册到AnimationHandler,并通过Choreographer实现精确时间控制和插值计算。
  • 使用场景:适用于需要改变对象实际属性的复杂动画效果,如非线性动画。
  • 实现非线性动画: 通过ValueAnimator或者ObjectAnimator结合Interpolator(插值器)来实现非线性动画。
  • 其中,插值器(Interpolator)定义了动画值随时间变化的速率。 Android提供了多种内置的插值器,如AccelerateInterpolator(加速插值器)、DecelerateInterpolator(减速插值器)、AccelerateDecelerateInterpolator(先加速后减速插值器)等。此外,你还可以自定义插值器来满足特定的需求。

2.StringBuffer和StringBuilder区别?

答:

3.jvm内存模型?

JVM内存模型的工作原理

JVM通过类加载器将Java代码编译成的字节码加载到内存中的运行时数据区,然后通过执行引擎将字节码翻译成底层系统的指令执行。在这个过程中,JVM还通过本地库接口调用其他语言编写的本地库来实现程序的功能。

  • 堆内存:是JVM中最大的一块,由新生代和老年代组成。默认情况下新生代按照8:1:1的比例来分配;

  • 方法区:存储类信息、常量、静态变量等数据,是线程共享的区域;

  • 栈:分为虚拟机栈和本地方法栈,主要用于方法的执行;

  • 线程共享:方法区+堆;

  • 线程独享:虚拟机栈+本地方法栈+程序计数器;

  • ‌**程序计数器**‌:这是线程私有的内存区域,用于记录当前线程执行的字节码行号。当线程执行Java方法时,程序计数器记录虚拟机字节码的地址;当执行Native方法时,程序计数器的值为空。

  • **Java虚拟机栈**‌:每个线程都有自己的Java虚拟机栈,用于存储局部变量表、操作栈、动态链接、方法出口等信息。每个方法执行时都会创建一个栈帧,方法执行完毕后,栈帧出栈。

  • ‌**本地方法栈**‌:用于存储本地方法的调用信息,也是线程私有的。本地方法通常由C语言实现。

  • ‌**堆**‌:这是JVM管理的最大一块内存区域,用于存储几乎所有的对象实例和数组数据。堆内存是垃圾收集器(GC)的主要工作区域,可以划分为新生代和老年代,以便更有效地管理内存。

  • ‌**方法区**‌:在JDK 1.8及以后版本中称为元空间,用于存储类信息、常量、静态变量和编译器编译后的代码等数据。所有线程共享这一区域。

4.线程池7大核心参数及原理?

  • corePoolSize:核心线程数
  • maximumPoolSize:最大线程数
  • keepAliveTime:最大空闲时间
  • unit:最大空闲时间单位
  • workQueue:任务队列
  • threadFactory:表示生成线程池中工作线程的线程工厂,用于创建线程一般用默认的即可。
  • handler:拒绝策略,
  1. 线程池刚创建时,里面没有一个线程。任务队列是作为参数传进来的。不过,就算队列里面有任务,线程池也不会马上执行它们。
  2. 当调用 execute() 方法添加一个任务时,线程池会做如下判断:
  3. 如果正在运行的线程数量小于 corePoolSize,那么马上创建线程运行这个任务;
  4. 如果正在运行的线程数量大于或等于 corePoolSize,那么将这个任务放入队列;
  5. 如果这时候队列满了,而且正在运行的线程数量小于maximumPoolSize,那么还是要创建非核心线程立刻运行这个任务;
  6. 如果队列满了,而且正在运行的线程数量大于或等于 maximumPoolSize,则线程池会抛出异常RejectExecutionException。
  7. 当一个线程完成任务时,它会从队列中取下一个任务来执行。
  8. 当一个线程无事可做,超过一定的时间(keepAliveTime)时,线程池会判断,如果当前运行的线程数大于 corePoolSize,那么这个线程就被停掉。所以线程池的所有任务完成后,它最终会收缩到 corePoolSize 的大小。
    img

5.Android多进程通信方式有哪些?各自的优缺点?

  • AIDL:功能强大,支持进程间一对多的实时并发通信,并可实现 RPC (远程过程调用);
  • Messenger:支持一对多的串行实时通信, AIDL 的简化版本;
  • Bundle:四大组件的进程通信方式,只能传输 Bundle 支持的数据类型;
  • ContentProvider:强大的数据源访问支持,主要支持 CRUD 操作,一对多的进程间数据共享,例如我们的应用访问系统的通讯录数据;
  • BroadcastReceiver:即广播,但只能单向通信,接收者只能被动的接收消息;
  • 文件共享:在非高并发情况下共享简单的数据;
  • Socket:通过网络传输数据;

img

6.Binder机制原理?

Binder原理

Binder是Android提供的一种效率更高、更安全的基于C/S架构的IPC通信机制,其本质也是调用系统底层的内存共享实现。

从进程角度来看Binder进程间通信原理:

binder

在Android系统中

  • 用户空间彼此不能共享
  • 内核空间可以共享
  • 用户空间进程通过open/ioctl等方式与内核空间通信
  • Client与Server通信的实现,是由Binder驱动在内核空间完成

在android中,有很多Service都是通过binder来通信的。这里要引入另一个重要的角色:ServiceManager。ServiceManager负责管理Server所提供的服务,同时响应Client的请求并为之分配相应的服务。

可以把ServiceManager(以下简称SM)比作通讯站,Client和Server是电话用户,Server首先要向通讯站注册号码,当Client拨打号码时,通讯站首先检索是否有该号码,如果有则转接给Client,否则不响应。

需要注意的是,Client一般认为是数据发送方,Server是数据接收方,两者并非固定不变的。如果Server在收到数据后主动向Client方发送数据,则两者身份互换。

Binder通信的完整流程如下:

Binder流程

  • Server向ServiceManager注册服务
  • Client向ServiceManager申请服务
  • SM作为守护进程,处理Client端请求,并管理所有Server端服务
  • BinderDriver位于Kernel层,是一切运作的基础

7.App启动流程?

  • 点击桌面App图标,Launcher进程采用Binder IPC向system_server进程发起startActivity请求;
  • system_server进程接收到请求后,向zygote进程发送创建进程的请求;
  • Zygote进程fork出新的子进程,即App进程;
  • App进程,通过Binder IPC向sytem_server进程发起attachApplication请求;
  • system_server进程在收到请求后,进行一系列准备工作后,再通过binder IPC向App进程发送scheduleLaunchActivity请求;
  • App进程的binder线程(ApplicationThread)在收到请求后,通过handler向主线程发送LAUNCH_ACTIVITY消息;
  • 主线程在收到Message后,通过发射机制创建目标Activity,并回调Activity.onCreate()等方法。
  • App便正式启动,开始进入Activity生命周期,执行完onCreate/onStart/onResume方法,UI渲染结束后便可以看到App的主界面。
    在这里插入图片描述

8.Handler机制原理?

Handler是Android系统中用于实现线程间通信和任务调度的一种机制。它基于Android的Looper、MessageQueue和Message三个核心组件实现。主要工作原理如下:

1.Message(消息):Message是一个包含要传递的数据和指令的对象。它可以携带整数、字符串、Bundle等不同类型的数据。当需要在不同线程之间传递数据或执行任务时,通常会创建一个Message并将其发送给Handler。

2.Handler(处理程序):Handler是用于处理Message的对象。它通常与一个特定的线程(通常是主线程)关联。通过Handler,您可以将Message发送到与其关联的线程的消息队列中,以便在那个线程中执行处理。

3.Looper(消息循环器):Looper是一个用于管理线程的消息队列的对象。每个线程都可以有一个Looper,它会在线程上创建一个消息队列,允许该线程接收并处理Message。主线程通常已经具有一个默认的Looper,而后台线程需要显式创建一个Looper。

4.MessageQueue(消息队列):MessageQueue是一个FIFO(先进先出)队列,用于存储待处理的Message。每个Looper都有一个关联的MessageQueue,Handler将Message发送到这个队列中,然后由Looper依次处理队列中的Message。

Handler机制的工作流程:

1.在主线程(或其他线程)上创建一个Handler对象,这个Handler会关联到当前线程的Looper。

2.在后台线程中,创建一个Message对象,可以将一些数据和处理指令放入这个Message。

3.使用Handler的sendMessage方法将Message发送到与Handler关联的Looper的MessageQueue中。

4.Looper在后台线程中不断轮询MessageQueue,当有新的Message到达时,将Message取出并交给Handler处理。

5.Handler收到Message后,可以根据Message中的指令执行相应的操作,通常是在主线程中更新UI。

6.如果需要定时任务或循环执行,可以使用Handler的postDelayed方法。

image

在这里插入图片描述

img

Handler的阻塞唤醒机制是怎么回事?

Handler的阻塞唤醒机制是指在Looper的MessageQueue中,当Message数量过多时,Looper会进入阻塞状态,直到有新的Message到来。当有新的Message到来时,Looper会唤醒并处理新的Message。

具体实现如下:

  • Looper在MessageQueue中维护了一个阻塞队列,当阻塞队列中的Message数量达到一定阈值时,Looper会进入阻塞状态。
  • 当有新的Message到来时,Looper会从阻塞队列中移除一个Message,并将其插入到MessageQueue中,从而唤醒Looper。
  • Looper唤醒后,会从MessageQueue中取出新的Message并处理

9.子线程可以更新ui吗?在Activity那个生命周期?

Andoird是不允许直接在子线程中更新UI的。原因是子线程中更新UI会引起线程不安全问题,导致界面卡顿掉帧。

在子线程中run方法中,通过handler.post或其他方式将更新UI的任务消息发送到UI线程,由UI线程更新UI。

Thread和Runnable的区别

  • Thread代表线程类。start()开启子线程,执行体为run()方法
  • Runnable只是一个接口,直接调用其run()方法,并不会开启子线程

下面介绍几种子线程更新UI的方法

方式一:Handler和Message

*方式二:在子线程中调用view.post*

方式三:在子线程中调用runOnUIThread

方式四:Handler.post()方法

10.Activity生命周期?A跳转B执行生命周期?弹出Dialog时Activity生命周期?

Activity的生命周期可以概括为以下几个阶段:

创建(Created):当Activity被创建时,系统会调用onCreate()方法。

启动(Started):当Activity变为用户可见时,系统会调用onStart()方法。

响应(Resumed):当Activity开始与用户交互时,系统会调用onResume()方法。此时,Activity处于Activity栈的顶部,是活跃的Activity。

暂停(Paused):当另一个Activity部分或完全覆盖当前Activity时,系统会调用onPause()方法。

停止(Stopped):当Activity不再可见时,系统会调用onStop()方法。

重新启动(Restarted):当Activity从停止状态恢复时,系统会调用onRestart()方法,然后继续生命周期的启动阶段。

销毁(Destroyed):当Activity需要被销毁时,系统会调用onDestroy()方法。

当在Activity A中弹出Dialog时,Activity A的生命周期不会发生变化,Dialog是Activity的一部分,不会影响Activity的生命周期。Dialog的显示和消失不会触发Activity的任何生命周期回调方法。
在这里插入图片描述
注: 当AActivity切换BActivity的所执行的方法:

AActivity:onCreate()->onStart()->onResume()->onPouse()
BActivity:onCreate()->onStart()->onResume()
AActivity:onStop()->onDestory()

当AActivity切换BActivity(此activity是以dialog形式存在的)所执行的方法:

AActivity:onCreate()->onStart()->onResume()->onPouse()
BActivity:onCreate()->onStart()->onResume()

11.屏幕旋转生命周期?

屏幕旋转时,Activity的生命周期变化如下‌:

  1. 屏幕旋转导致Activity重新创建‌:当屏幕旋转时,当前的Activity会被销毁并重新创建。这是因为屏幕旋转会导致布局的改变,需要重新加载适配新屏幕方向的布局资源‌12。

  2. 生命周期方法调用顺序‌:

    ‌**onPause()**‌:当前Activity即将失去焦点时调用,应停止处理耗时操作、保存用户数据或释放资源‌3。

    ‌**onStop()**‌:当前Activity完全不可见时调用,应取消注册监听器、停止动画或释放其他资源‌3。

    ‌**onDestroy()**‌:当前Activity被销毁时调用,可以在此方法中释放所有资源‌3。

    ‌**onCreate()**‌:创建新的Activity时调用,用于初始化Activity的状态和布局‌3。

    ‌**onStart()**‌:Activity即将变为可见状态时调用‌3。

    ‌**onResume()**‌:Activity变为可见状态时调用,通常在此方法中注册监听器、启动动画或获取位置更新等操作‌3。

12.Activity启动模式及应用场景?

Activity的四种启动模式

  1. standard(标准模式)
    • 行为:默认的启动模式,每次启动Activity时都会创建一个新的实例,并将其放入任务栈中。所以,任务栈中可能同时存在该Activity的多个实例。
    • 应用场景:每次打开都是新内容或新页面。比如新闻内容列表,每次打开都是新页面。
  2. singleTop(单顶模式,or栈顶复用模式)
    • 行为:如果任务栈的栈顶已经是该Activity的实例,则不会创建新的实例,而是直接复用栈顶的Activity实例。如果栈顶不是该Activity的实例,则会创建新的实例并放入栈中。
    • 应用场景:适用于那些不需要多个实例的Activity,比如通知栏消息点击打开应用
  3. singleTask(单任务模式,or栈内复用模式)
    • 行为:如果任务栈中已经存在该Activity的实例,则不会创建新的实例,而是将任务栈中该实例以上的所有Activity实例都移除,让该实例位于栈顶。如果任务栈中不存在该Activity的实例,则创建新的实例。
    • 应用场景:适用于作为应用程序入口的Activity,如APP的主页或主界面!!!确保无论从哪里进入应用,都回到主页面而不是在主页面上方叠加新的页面。
  4. singleInstance(单实例模式)
    • 行为:该模式下的Activity会单独位于一个任务栈中。无论从哪里启动该Activity,都会重用这个实例,并且该Activity会单独占据一个任务栈。
    • 生命周期:走(onPause) -> onNewIntent() -> onResume
    • 应用场景: 适用于与其他完全隔离的Activity,如来电显示页面; 适用于那些需要全局唯一实例的Activity,比如系统级的服务Activity或者需要全局共享数据的Activity。

主Activity一般用哪种启动模式

对于主Activity(即应用的首页或主界面),一般推荐使用singleTopsingleTask启动模式

  • 使用singleTop模式:如果主Activity已经位于任务栈的栈顶,再次启动它时不会创建新的实例,而是直接复用现有的实例。 这可以避免不必要的Activity创建和销毁,提高应用的性能和用户体验。
  • 使用singleTask模式:如果主Activity在任务栈中存在,无论它位于栈的哪个位置,都会将它之上的所有Activity实例移除, 并将其置于栈顶。这可以保证用户无论通过哪种方式回到应用,都会直接看到主Activity,并且 主Activity上方不会有其他Activity遮挡。

最终选择哪种模式,需要根据应用的具体需求和用户体验来决定。如果应用结构相对简单,用户行为也比较单一,使用singleTop模式可能就足够了。如果应用结构复杂,需要处理多种用户场景和跳转逻辑,那么使用singleTask模式可能更加合适。

5、使用方式

(1)在AndroidManifest.xml,指定android:launchMode=“singleInstance”;

(2)通过Intent设置标志位,addFlags(NEW_TASK、CLEAR_TOP、SINGLE_TOP)

13.java中extends和super的区别?

‌**Java泛型中的extendssuper关键字用于限定泛型类型的边界,但它们的作用和用法有所不同。**‌

extends和super的区别

  1. 使用场景‌:
    • extends‌用于指定泛型的上界,表示泛型参数可以是某个类的子类或本身,类似于“is-a”的关系。例如,T extends Number表示类型T必须是Number类或其子类‌。
    • super‌用于指定泛型的下界,表示泛型参数可以是某个类的父类或本身,类似于“has-a”的关系。例如,T super Integer表示类型T必须是Integer类或其父类‌。
  2. 使用效果‌:
    • extends‌限制的类型参数可以读取但不能写入,因为使用extends限制后,编译器无法确定泛型类型的具体类型,所以只能让读操作成立,而写操作不成立,否则会存在类型不安全的风险‌。
    • super‌限制的类型参数可以写入但不能读取,因为使用super限制后,泛型类型一定是某个父类或本身,所以只能让写操作成立,而读操作不成立,否则会导致类型转换错误‌。

14.String s1 = new String(“abc”) 创建了几个字符串对象?

‌**在Java中,表达式 String s1 = new String("abc") 创建的字符串对象数量取决于字符串常量池中是否已经存在字符串 “abc”。**‌

  1. 如果字符串常量池中不存在字符串 “abc”,则创建两个对象‌:
    • 一个是在堆空间中通过 new 关键字创建的新对象。
    • 另一个是在字符串常量池中创建的字符串常量 "abc"‌。
  2. 如果字符串常量池中已经存在字符串 “abc”,则只创建一个对象‌:
    • 这种情况下,new String("abc") 会在堆空间中创建一个新的对象,但由于 “abc” 已经在常量池中存在,所以不会在常量池中重复创建‌。

字符串常量池的作用

字符串常量池是Java中的一个机制,用于存储唯一的字符串常量,以节省内存。当创建一个字符串时,JVM会首先检查常量池中是否已经存在相同内容的字符串。如果存在,则直接返回常量池中的引用;如果不存在,则创建一个新的字符串对象并放入常量池中‌。

15.Android中自定义view的流程以及onMeaure()方法调用时机?

在 Android 中,自定义 View 的绘制流程主要包括测量布局绘制三个关键步骤。具体来说,[自定义 View](https://so.csdn.net/so/search?q=自定义 View&spm=1001.2101.3001.7020) 的绘制涉及重写系统的 onMeasure()onLayout()onDraw() 方法

自定义控件步骤:

1、创建View

2、处理View的布局

3、绘制View

4、与用户进行交互

5、优化已定义的View

在Android中,自定义View时,onMeasure()方法是在视图层次结构中的父视图和子视图之间协商布局时调用的。它的主要职责是设置视图的宽度和高度。

onMeasure()方法的调用时机通常如下:

  1. 当父视图对自己的子视图进行布局时,会先调用子视图的onMeasure()方法来确定子视图的尺寸。
  2. 当你将一个自定义视图添加到布局文件中,或者在代码中动态创建并添加到容器中时。
  3. 当父视图的尺寸发生改变时,也会重新对子视图进行尺寸测量。

16. View的绘制流程?

img

1). View系统的绘制流程会从ViewRootImpl的performTraversals()方法中开始,performTraversals()的意思是:执行遍历,Traversals:遍历的意思

performTraversals会分别调用 performMeasure, performLayout,performDraw

而这三个方法,我想你应该能猜到,他们会启动onMesure,onLayout,onDraw方法

2). ViewRoot中包含了窗口的总容器DecorView,ViewRoot中的performTraversal()方法会依次调用decorView的measure、layout、draw方法,从而完成view树的绘制。

3). measure()方法,layout(),draw()三个方法主要存放了一些标识符,来判断每个View是否需要再重新测量,布局或者绘制

View树的绘制是一个递归的过程,从ViewGroup一直向下遍历,直到所有的子view都完成绘制

总结: View的整个绘制流程可以分为以下三个阶段:

  • measure: 判断是否需要重新计算View的大小,需要的话则计算;每个View的控件的实际宽高都是由父视图和本身视图决定的
  • layout: 判断是否需要重新计算View的位置,需要的话则计算;
  • draw: 判断是否需要重新绘制View,需要的话则重绘制。
  • measure()、layout()、draw(),其内部又分别包含了onMeasure()、onLayout()、onDraw()三个子方法。

17.为什么okhttp中核心线程数是0?

OkHttp的线程池设计为核心线程数为0,最大线程数为Integer.MAX_VALUE,并且使用SynchronousQueue作为任务队列。这种设计的主要目的是为了快速响应网络请求,避免线程的闲置和资源的浪费。具体来说:

  • 快速响应请求‌:由于核心线程数为0,当有新的请求到来时,线程池会立即创建一个新线程来处理该请求,而不需要等待空闲线程。这样可以确保每个请求都能立即得到处理,从而提高响应速度。
  • 资源利用效率‌:由于线程池的最大线程数设置为Integer.MAX_VALUE,理论上可以创建无限多的线程来处理请求。但实际上,OkHttp通过内部机制控制了请求的最大并发数,通常不会达到这个上限。这种设计可以在高并发场景下提供足够的处理能力,同时避免了过多的线程占用系统资源。
  • SynchronousQueue的使用‌:SynchronousQueue是一个无缓冲的阻塞队列,每个put操作必须等待一个take操作,反之亦然。这意味着每当有一个任务提交时,必须有一个线程在等待执行这个任务,从而确保了任务的即时处理。
  • 线程的回收‌:空闲线程在60秒后会被终止,这样可以避免长时间闲置的线程占用系统资源。这种设计使得线程池能够根据实际需求动态调整线程数量,提高资源利用率。

综上所述,OkHttp的线程池设计通过核心线程数为0、最大线程数为Integer.MAX_VALUE以及使用SynchronousQueue,实现了高并发处理和资源的高效利用,从而提升了网络请求的处理速度和系统的整体性能。

18.okhttp拦截器原理?

OkHttp最核心的工作是在 getResponseWithInterceptorChain() 中进行,在进入这个方法分析之前,我们先来了 解什么是责任链模式,因为此方法就是利用的责任链模式完成一步步的请求。责任链顾名思义就是由一系列的负责者构成的一个链条,类似于工厂流水线

一、责任链设计模式

①定义:
它为请求创建了一个接收者对象的链。为了避免请求发送者与多个请求处理者耦合在一起,于是将所有请求的处理者通过前一对象记住其下一个对象的引用而连成一条链,当有请求发生时,可将请求沿着这条链传递,直到有对象处理它为止。(责任链模式也叫职责链模式)

在责任链模式中,每一个对象对其下家的引用而接起来形成一条链。请求在这个链上传递,直到链上的某一个对象 决定处理此请求。客户并不知道链上的哪一个对象最终处理这个请求,系统可以在不影响客户端的 情况下动态的重 新组织链和分配责任。处理者有两个选择:承担责任或者把责任推给下家。一个请求可以最终不被任何接收端对象 所接受。

②为什么要使用责任链模式
原因如下:

  • 解耦
  • 实现单依职责原则

二、默认的5大拦截器有哪些?

  • RetryAndFollowUpInterceptor(重试和重定向拦截器)
  • 第一个接触到请求,最后接触到响应;负责判断是否需要重新发起整个请求
  • BridgeInterceptor(桥接拦截器)
  • 补全请求,并对响应进行额外处理
  • CacheInterceptor(缓存拦截器)
  • 请求前查询缓存,获得响应并判断是否需要缓存
  • ConnectInterceptor(链接拦截器)
  • 与服务器完成TCP连接 (Socket)
  • CallServerInterceptor(请求服务拦截器)
  • 与服务器通信;封装请求数据与解析响应数据(如:HTTP报文)

三、okhttp工作的大致流程

1.整体流程

(1)、当我们通过**OkhttpClient创立一个okHttpClient 、Request 、**Call,并发起同步或者异步请求时;

(2)、okhttp会通过Dispatcher对我们所有的Call(*Real*Call实现类)进行统一管理,并通过execute()及enqueue()方法对同步或者异步请求进行执行
(3)、execute()及enqueue()这两个方法会最终
调用RealCall中的getResponseWithInterceptorChain()方法,从阻拦器链中获取返回结果;**
(4)、拦截器链中,依次通**过ApplicationInterceptor**(*应用拦截器*)****、RetryAndFollowUpInterceptor(重定向阻拦器)、BridgeInterceptor(桥接阻拦器)、CacheInterceptor(缓存阻拦器)、ConnectInterceptor(连接阻拦器)、NetwrokInterceptor(网络拦截器)、CallServerInterceptor(请求阻拦器)对请求依次处理,与服务的建立连接后,获取返回数据,再经过上述阻拦器依次解决后,最后将结果返回给调用方。

img

2.细化分析:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • ApplicationInterceptor: 应用拦截器,通过addInterceptor添加,拿到的是原始请求,可以添加一些自定义header、通用参数、参数加密、网关接入等等。
  • RetryAndFollowUpInterceptor:重试和重定向拦截器,处理错误重试和重定向
  • BridgeInterceptor:桥接拦截器,主要工作是为请求添加cookie、添加固定的header,比如Host、Content-Length、Content-Type、User-Agent等等,然后保存响应结果的cookie,如果响应使用gzip压缩过,则还需要进行解压。
  • CacheInterceptor:缓存拦截器,如果命中缓存则不会发起网络请求。
  • ConnectInterceptor:连接拦截器,内部会维护一个连接池,负责连接复用、创建连接(三次握手等等)、释放连接以及创建连接上的socket流。
  • NetworkInterceptors:网络拦截器,用户自定义,通常用于监控网络层的数据传输。
  • CallServerInterceptor:网络请求拦截器,在前置准备工作完成后,真正发起了网络请求。

3.总结:

整个OkHttp功能的实现就在这五个默认的拦截器中,所以先理解拦截器模式的工作机制是先决条件。这五个拦截 器分别为: 重试拦截器、桥接拦截器、缓存拦截器、连接拦截器、请求服务拦截器。每一个拦截器负责的工作不一 样,就好像工厂流水线,最终经过这五道工序,就完成了最终的产品。

但是与流水线不同的是,OkHttp中的拦截器每次发起请求都会在交给下一个拦截器之前干一些事情,在获得了结果之后又干一些事情。整个过程在请求向是顺序的,而响应向则是逆序。

当用户发起一个请求后,会由任务分发起 Dispatcher 将请求包装并交给重试拦截器处理。

1、重试拦截器在交出(交给下一个拦截器)之前,负责判断用户是否取消了请求;在获得了结果之后,会根据响应码判断是否需要重定向,如果满足条件那么就会重启执行所有拦截器。

2、桥接拦截器在交出之前,负责将HTTP协议必备的请求头加入其中(如:Host)并添加一些默认的行为(如:GZIP 压缩);在获得了结果后,调用保存cookie接口并解析GZIP数据。

3、缓存拦截器顾名思义,交出之前读取并判断是否使用缓存;获得结果后判断是否缓存。
4、连接拦截器在交出之前,负责找到或者新建一个连接,并获得对应的socket流;在获得结果后不进行额外的处
理。
5、请求服务器拦截器进行真正的与服务器的通信,向服务器发送数据,解析读取的响应数据。 在经过了这一系列的流程后,就完成了一次HTTP请求!

19.okhttp中 应用层拦截器和网络层拦截器区别?

20.synchronized关键字使用场景?

22.ThreadLocal原理?

23.jvm垃圾回收机制?回收算法?

24.RecyclerView缓存机制及原理?各自调用时机?

25.TV开发焦点问题?如何记忆焦点?

26.屏幕适配原理?AutoSize,今日头条原理?

27.Android中内存优化?

28.什么是ANR?ANR类型及发生原因和解决办法?

29.内存泄漏是什么?发生原因?如何排查?解决方法?

30.ArrayList和LiskedList区别?

31.HashMap底层实现原理?扩容原理?

32.Android中开启多线程的方式?优缺点?

33.如何让多个线程按顺序执行?

34.OKHTTP使用了哪些设计模式及优缺点?

35.setContentView的绘制流程?

36.App打包流程?

37.Apk安装过程?

38.Android常用的设计模式有哪些?说说你的理解?

39.retrofit原理?

40.rxjava原理?如何切换线程?map操作符和flatmap区别?背压?

41.线程池核心参数有哪些?使用流程?拒绝策略?

42.jvm内存模型?

43.GC回收机制?如何判断一个对象是否能被回收?gc回收算法?

44.synchronized和volatile区别?

45.同步锁?重入锁?可重入锁?

46.java多线程用法?如何让多个线程按顺序执行?

47.LiveDate原理?使用过程中遇到的问题?解决方法?

48.viewmodel原理?

49.lifecycle原理?

50.协程原理?优缺点?

51.Java封装、多态、继承是什么?

52.Java中抽象和接口的区别?

53.Java中引用类型有哪些?概念?

54.Java中数组、树、链表有啥区别?HashMap原理?

答:1.数组:定义:数组是用于储存多个相同类型数据的[集合](https://so.csdn.net/so/search?q=集合&spm=1001.2101.3001.7020),是有序的元素序列。​       特点:数组就是在[内存](https://so.csdn.net/so/search?q=内存&spm=1001.2101.3001.7020)中开辟一块连续的、大小相同的空间,用来存储数据.​                    可以通过下标访问的方式访问成员,查询效率高​                    增删操作会给系统带来性能消耗[保证数据下标越界的问题,需要动态扩容]2.树:定义:一棵树(tree)是由n(n>0)个元素组成的[有限集合](https://baike.baidu.com/item/有限集合),​               每个元素称为[结点](https://baike.baidu.com/item/结点)(node);​               有一个特定的结点,称为[根结点](https://baike.baidu.com/item/根结点/9795570)或根(root);​               除根结点外,其余结点被分成m(m>=0)个互不相交的有限集合,而每个[子集](https://baike.baidu.com/item/子集)又都是一棵树(称为原树的子树)3.链表:定义:链表是一种物理[存储单元](https://blog.csdn.net/qq_39151085/article/details/109669228)上非连续、非顺序的[存储结构](https://blog.csdn.net/qq_39151085/article/details/109669228)[数据元素](https://blog.csdn.net/qq_39151085/article/details/109669228)的逻辑顺序是通过链表中的[指针](https://baike.baidu.com/item/指针/2878304)链接次序实现的,每一个链表都包含多个节点,节点又包含两个部分,一个是数据域(储存节点含有的信息)分为单向链表和双向链表添加:添加时只需要修改指针的指向地址就可以,无需要像数组那样开辟新的内存空间删除:删除时同样修改指针的指向地址就可以s特点:> 灵活的空间要求,存储空间不要求连续
>
> 不支持下标的访问.支持顺序的遍历搜索
>
> 针对增删操作找到对应的节点改变链表的头尾指向即可,无需移动元素存储位置

55.Java中的线程模型?为啥i++=2?

56.Java中泛型的理解?

57.类的加载器,双亲机制,Android的类加载器?

58.Java的虚拟机JVM的两个内存:栈内存和堆内存的区别是什么?

59.Android各大版本区别?如何适配?

60.Http和https的区别?

61.TCP三次握手和四次挥手过程?

62.TCP、UDP、Http、WebSocket区别?

63.对称加密和非对称加密?

64.组件化、模块化、插件化区别?

65.插件化原理?

66.Android中如何混淆以及要注意的问题?

67.Android中SDK开发如何加密及需要注意的问题?

68.Android中的保活方式有哪些?

69.Android多屏幕适配方案及原理?

70.Android中性能优化方式有哪些?

71.启动优化如何做?内存优化的方式?

72.自定义View的流程?3种测量模式区别?

73.Android中事件分发机制?

74.滑动冲突处理方式?

75.Android中线程通信方式有哪些?

76.服务两种启动方式生命周期如何执行?

77.断点续传原理?

78.Android中加密方式有哪些?如何进行加固处理?

79.Android签名机制v1、v2、v3的区别?

80.项目中遇到哪些问题?你是如何解决的?

81.蓝牙通信协议有哪些?数据格式?

82.音频编解码问题?PCM转aac?

83.视频播放器内核如何切换?

84.视频无缝播放如何实现?

85.视频列表跳转详情播放进度保存?

86.视频列表跳转详情播放状态同步?

87.视频边播边播如何实现?缓存实现?

88.播放时默认无声和按音量键调节声音的实现?

89.视频播放关键帧处理?

90.视频拖动时进度回弹处理?

91.视频小窗切换全屏实现?

92.视频播放在手机锁屏、退到后台和杀手app播放状态处理?

93.视频播放进度同步和清除进度处理?

94.视频播放卡顿处理?

95.视频全屏退到小窗进度、状态同步?

96.视频高宽不能全部充满屏幕,有黑边的问题?

97.在视频默认状态或暂停时从某个时间节点开始播放?

98.4g和WiFi切换流量提示?

99.串口通信协议有哪些?

100.常见的串口类型有哪些?

101.串口帧数据的组成

102.怎么排查数据收发问题,自发自收检测?

103.遇到不能发送数据,在接收数据后才能发送要怎么解决?

104.丢数据,数据被拆分要怎么解决?

105.串口无响应如何排查?

106.常见的数据检验方式,在数据比较多的情况,用啥方法转换能避免内存溢出问题?

107.串口设备主从通信方式?

108.串口广播组播的理解?

109.多个进程使用串口数据如何封装接口?

110.是否有wifi bt usb gps nfc 的串口调试经验?

111.scoket相关?tcp、udp、mqtt、websocket?

112.串口通信拆包、分包、丢包处理?

113.线程池原理?

114.livedata和stateFlow原理?

115.flow、stateflow、sharedflow、livedata区别?实现原理?

116.ANR日志怎么抓取?问题查找?分析?解决方法?如何设计一个anr日志手机框架?

117.动画的实现方式?帧动画缺点?如何优化?

118.跨进程实现有哪几种方式?原理?如何实现?

119.kotlin高级函数有哪些?各种区别?原理?

120.kotlin协程是什么?原理?

121.kotlin优点?为啥使用?

122.kotlinobject函数是啥?有啥作用?

123.kotlin中apply、also、let、run区别与联系?应用场景?

124.kotlinz中如何实现懒加载?by lazy和lateinit区别?

125.viewmodel原理?

126.livedata优点?缺点?数据倒灌和粘性事件咋解决?

127,请简述下什么是kotlin?它有什么特性?

128.Kotlin 中注解 @JvmOverloads 的作用?

129.Kotlin中的MutableList与List有什么区别?

130.kotlin实现单例的几种方式?

131.kotlin实现单例的几种方式?

132.什么是委托属性?简单说一下应用场景?

133.kotlin中Unit的应用以及和Java中void的区别?

134.Kotlin 中 infix 关键字的原理和使用场景?

135.Kotlin中的可见性修饰符有哪些?相比于 Java 有什么区别?

136.你觉得Kotlin与Java混合开发时需要注意哪些问题?

137.在Kotlin中,何为解构?该如何使用?

138.在Kotlin中,什么是内联函数?有什么作用?

139.谈谈kotlin中的构造方法?有哪些注意事项?

140.谈谈Kotlin中的Sequence,为什么它处理集合操作更加高效?

141.请谈谈Kotlin中的Coroutines,它与线程有什么区别?有哪些优点?

142.Kotlin中该如何安全地处理可空类型?

143.Kotlin中的?.然后后面调用方法如果为空的情况下是什么?如果是调用变量是什么情况?

144.说说 Kotlin中 的 Any 与Java中的 Object 有何异同?

145.Kotlin中的数据类型有隐式转换吗?为什么?

146.Kotlin 中集合遍历有哪几种方式?

147.为什么协程比线程要轻量?

148.协程Flow是什么,有哪些应用场景?

149.协程Flow的冷流和热流是什么?

150.协程中可能遇到哪些问题?

151.解释一下extension函数。?

152.kotlin中的null safety是什么意思?

153.kotlin中什么是并发?

154.对于Kotlin中的协程有什么理解?

155.协程比线程更高效的原因是什么?

156.协程框架中主要组成部分?

157.关于协程作用域CoroutineScope?

158.解释协程中的调度程序Dispatcher?

159.关于协程中的作业Job?

160.关于协程中的作业Job?

161.简单说说suspend挂起函数?

162.从另一个挂起函数调用一个挂起函数会发生什么?

163.关于协程中的挂起和阻塞有什么区别?

164.启动协程的launch() 和 async() 有什么区别?在某些情况下应该使用哪个?

165.区分 Kotlin 中的 launch / join 和 async / await

166.协程中的 GlobalScope 以及为什么要避免它?

167.如果协程内部抛出异常会怎么样?

168.CoroutineScope.async {} 中的异常如何工作?

169.平常使用协程时有碰到哪些错误?

170.使用 Kotlin 协程时有哪些好的做法可以遵循?

171.Kotlin协程比Rxjava/RxKotlin好在哪里?

172.Kotlin中的数据类型有隐式转换吗?为什么?

173.Kotlin中集合遍历有哪几种方式?

174.谈谈kotlin中的构造方法?有哪些注意事项?

175.谈谈Kotlin中的Sequence,为什么它处理集合操作更加高效?

176.说说Kotlin中的Any与Java中的Object有何异同?

177.Kotlin中的数据类型有隐式转换吗?为什么?

178.理解线程间通信?

179.工作者线程(workerThread)与主线程(UI线程)的理解

180.通过Handler在线程间通信的原理

181.子线程发消息到主线程进行更新 UI,除了 handler 和 AsyncTask,还有什么?

182.子线程中能不能 new handler?为什么?

183.Handler、 Thread 和 HandlerThread 的差别

184.当Activity有多个Handler的时候,Message消息是否会混乱?怎么样区分当前消息由哪个Handler处理?

185.线程更新UI导致崩溃的原因?

186.ANR应用无响应

187.AsyncTask(异步任务)的工作原理

188.AsyncTask使用在哪些场景?它的缺陷是什么?如何解决?

189.Android中动画的类型:

190.理解Activity、View、Window三者之间的关系

191.Activity、Dialog、PopupWindow、Toast 与Window的关系

192.Android中Context详解:

193.讲解一下Context

194.Android常用的数据存储方式(5种)

195.SharedPreference跨进程使用会怎么样?如何保证跨进程使用安全?

196.数据库的操作类型有哪些,如何导入外部数据库?

197.SQLite支持事务吗? 添加删除如何提高性能?

198.Android垃圾回收机制和程序优化System.gc( )

199.为什么图片需要用软引用,MVP模式中的view接口用弱引用

200.Android平台的优势和不足

201.Android中任务栈的分配

202.Activity组件生命周期、四种启动模式

203.Activity的启动过程(不要回答生命周期)

204.保存Activity状态

205.如何修改 Activity 进入和退出动画

206.Service组件

207.什么是 IntentService?有何优点?

208.是否使用过 IntentService,作用是什么, AIDL 解决了什么问题?

209.BoradcastReceiver组件

210.配置文件静态注册和在代码中动态注册两种方式的区别

211.ContentProvider(内容提供者)组件

212.Fragment中add与replace的区别?

213.FragmentPagerAdapter 与 与 FragmentStatePagerAdapter 的区别与使用场景?

214.Activity静态添加Fragment

215.Activity动态加载Fragment

216.Intent

217.ViewPager

218.关于Fragment中的控件的事件的监听

219.使用View绘制视图

220.View的绘制流程

221.View,ViewGroup事件分发

222.Android的事件传递(分发)机制

223.Android中touch事件的传递机制是怎样的?

224.View的分发机制,滑动冲突

225.Android中跨进程通讯的几种方式

226.Android 线程间通信有哪几种方式(重要)

227.AIDL理解

228.AIDL 的全称是什么?如何工作?能处理哪些类型的数据?

229.什么是 AIDL?如何使用?

230.Android中页面的横屏与竖屏操作

231.横竖屏切换的Activity 生命周期变化?

232.获取手机中屏幕的宽和高的方法

233.内存泄漏的相关原因

234.Android内存泄漏及管理

235.Android平台的虚拟机Dalvik

236.Android中的Binder机制

237.Android中的缓存机制

238.Android 中图片的三级缓存策略

239.Glide三级缓存

240.HybridApp WebView和JS交互

241.RecyclerView和ListView的区别

242.简述一下RecyclerView缓存机制?

243.recyclerView嵌套卡顿解决如何解决

244.Universal-ImageLoader,Picasso,Fresco,Glide对比

245.Xutils, OKhttp, Volley, Retrofit对比

246.请解释下 Android 程序运行时权限与文件系统权限的区别?

247.Framework 工作方式及原理,Activity 是如何生成一个 view 的,机制是什么?

248.Android 判断SD卡是否存在

249.Android与服务器交互的方式中的对称加密和非对称加密是什么?

250.SurfaceView和GLSurfaceView

251.说说JobScheduler

252.说说WorkManager

253.谈一谈startService和bindService的区别,生命周期以及使用场景?

254.Service如何进行保活?

255.热修复的原理

256.JNI

257.谈谈对Android NDK的理解

258.Android设计模式之MVC

259.mvc/mvp/mvvm

260.设计模式的六大原则

261.Android中的性能优化相关问题

262.Bitmap的使用及内存优化

263.性能优化(非常重要)

264.Android对HashMap做了优化后推出的新的容器类是什么?

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

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

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

267.Kotlin 如何在 Android 上运行?

268.为什么要使用 Kotlin?

269.用var和val声明变量有什么区别?

270.用val和const声明变量有什么区别?

271.Kotlin 中如何保证 null 安全?

272.安全调用(?.)和空值检查(!!)有什么区别?

273.Kotlin 中是否有像 java 一样的三元运算符?

274.Kotlin 中的 Elvis 运算符是什么?

275.如何将 Kotlin 源文件转换为 Java 源文件?

276.你觉得Kotlin与Java混合开发时需要注意哪些问题?

277.@JvmStatic、@JvmOverloads、@JvmFiled 在 Kotlin 中有什么用?

278.Kotlin 中的数据类是什么?

279.Kotlin中的数据类型有隐式转换吗?为什么?

280.Kotlin中可以使用int、double、float等原始类型吗?

281.Kotlin 中的字符串插值是什么?

282.Kotlin 中的解构是什么意思?

283.在Kotlin中,何为解构?该如何使用?

284.如何检查一个lateinit变量是否已经初始化?

285.Kotlin 中的 lateinit 和 lazy 有什么区别?

286.操作符和=操作符有什么区别?

287.Kotlin 中的 forEach 是什么?

288.Kotlin 中的伴生对象是什么?

289.kotlin中Unit的应用以及和Java中void的区别?

290.Kotlin 中的 Java 静态方法等价物是什么?

291.Kotlin 中的 FlatMap 和 Map 有什么区别?

292.Kotlin中可以使用new关键字实例化一个类对象吗?

293.Kotlin 中的可见性修饰符是什么?

294.Kotlin中的可见性修饰符有哪些?相比于 Java 有什么区别?

295.如何在 Kotlin 中创建 Singleton 类?

296.Kotlin 中的初始化块是什么?

297.Kotlin 中的构造函数有哪些类型?

298.主构造函数和次构造函数之间有什么关系吗?

299.构造函数中使用的默认参数类型是什么?

300.谈谈kotlin中的构造方法?有哪些注意事项?

301.Kotlin 中的扩展函数是什么

302.kotlin基础: From Java To Kotlin

303.Kotlin 中什么时候使用 lateinit 关键字?

304.Kotlin 的延迟初始化: lateinit var 和 by lazy

305.Kotlin Tips:怎么用 Kotlin 去提高生产力(kotlin优势)

306.Kotlin数组和集合

307.Kotlin中的MutableList与List有什么区别?

308.Kotlin集合操作符

309.Kotlin 中集合遍历有哪几种方式?

310.说一下Kotlin的伴生对象(关键字companion)

311.Kotlin 顶层函数和属性

312.Kotlin 中的协程是什么?

313.Kotlin Coroutines 中的挂起函数是什么?

314.Kotlin Coroutines 中 Launch 和 Async 有什么区别?

315.Kotlin Coroutines 中的作用域是什么?

316.Kotlin Coroutines 中的异常处理是如何完成的?

317.在 Kotlin 中如何在 switch 和 when 之间进行选择?

318.Kotlin 中的 open 关键字是做什么用的?

319.什么是 lambdas 表达式?

320.Kotlin 中的高阶函数是什么?

321.Kotlin 中的扩展函数是什么?

322.Kotlin 中的中缀函数是什么?

323.Kotlin 中的内联函数是什么?

324.Kotlin 中的 noinline 是什么?

325.Kotlin 中的具体化类型是什么?

326.Kotlin 中的运算符重载是什么?

327.解释在 Kotlin 中 let、run、with 和 apply 的用例。

328.kotlin中with、run、apply、let函数的区别?一般用于什么场景?

329.Kotlin 中的 pair 和 Triple 是什么?

330.Kotlin 中的标签是什么?

331.使用密封类而不是枚举有什么好处?

332.协程是什么

333.kotlin中关键字data的理解?相对于普通的类有哪些特点?

334.谈谈Kotlin中的Sequence,为什么它处理集合操作更加高效?

335.说说 Kotlin中 的 Any 与Java中的 Object 有何异同?

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com