Android面试题

简单

android 基础

对于面向对象的六大基本原则了解多少
  1. 单一职责(Single Responsibility Principle):一个类只做一件事,可读性提高
  2. 里式替换原则( Liskov Substitution Principle):依赖继承和多态,就是能用父类的地方就可以用子类替换,用子类的但不能用父类。
  3. 依赖倒置原则(Dependence Inversion Principle):依赖抽象,就是模块之间的依赖通过抽象发生。
  4. 开闭原则(Open-Close Principle):不管是实体类,模块还是函数都应该遵循对扩展开放对修改关闭。还是要依赖封装和继承
  5. 接口隔离原则(Interface Segregation Principle):一个类对另一个类的依赖应该建立在最小的接口上,如果接口太大,我们需要把它分割成一些更细小的接口,也是为了降低耦合性
  6. 迪米特原则(Law of Demeter ):也称最少知识原则,也就是说一个类应该对自己需要耦合或者调用的类知道的最少,只需知道该方法即可,实现细节不必知道。
view的事件分发

1.触发过程:Activity->Window->DocerView->ViewGroup->View,View不触发再返回由父级处理依次向上推。 2.在每个阶段都要经过三个方法 dispatchTouchEvent(分发)、onInterceptTouchEvent(拦截)、onTouch(处理)

大体流程: Activity中走了Window 的 dispatch,Window 的 dispatch 方法直接走了 DocerView 的 dispatch 方法,DocerView 又直接分发给了 ViewGroup,ViewGroup 中走的是 onInterce 判断是否拦截,拦截的话会走 onTouch 来处理,不拦截则继续下发给 View。到 View 这里已经是最底层了,View 若继续不处理,那就调用上层的 onTouch 处理,上层不处理继续往上推。

launch mode

(1) standard:标准的启动模式。

(2) singleTop:单一顶部模式

如果 Activity 已经被开启,并且处于任务栈的栈顶,就不会创建新的 Activity,而是复用这个已经开启的 Activity。为了防止出现一些奇怪的用户体验,推荐使用单一顶部模式,整个任务栈可以有多个实例存在.应用场景:短信发送界面.

(3)singletask:单一任务栈

在整个任务栈里面只允许有一个当前 Activity 的实例存在如果要开启的 Activity 在任务栈中已经存在,直接复用这个已经存在的 Activity,并且把这个 Activity 上面的所有的其他 Activity 给清空应用场景:如果一个 Activity 非常消耗内存和 cpu 资源,建议把这个 Activity 做成 singletask 的模式。浏览器的 browserActivity

(4)singleinstance:单一实例.

整个手机操作系统只有一个实例存在,并且是运行在自己单独的任务栈里面.应用场景:通话界面的 Activity

请谈谈 invalidate() 和 postInvalidate() 方法的区别和应用场景?

参考答案:

  1. invalidate()用来重绘UI,需要在UI线程调用。
  2. postInvalidate()也是用来重新绘制UI,它可以在UI线程调用,也可以在子线程中调用,postInvalidate()方法内部通过Handler发送了一个消息将线程切回到UI线程通知重新绘制,并不是说postInvalidate()可以在子线程更新UI,本质上还是在UI线程发生重绘,只不过我们使用postInvalidate()它内部会帮我们切换线程
Fragment 的生命周期?

参考答案:

1,onAttach:fragment 和 activity 关联时调用,且调用一次。在回调中可以将参数 content 转换为 Activity保存下来,避免后期频繁获取 activity。

2,onCreate:和 activity 的 onCreate 类似

3,onCreateView:准备绘制 fragment 界面时调用,返回值为根视图,注意使用 inflater 构建 View时 一定要将 attachToRoot 指明为 false。

4,onActivityCreated:activity 的onCreated 执行完时调用

5,onStart:可见时调用,前提是 activity 已经 started

6,onResume:交互式调用,前提是 activity 已经 resumed

7,onPause:不可交互时调用

8,onStop:不可见时调用

9,onDestroyView:移除 fragment 相关视图时调用

10,onDestroy:清除 fragmetn 状态是调用

11,onDetach:和 activity 解除关联时调用

从生命周期可以看出,他们是两两对应的,如 onAttach 和 onDetach ,

onCreate 和 onDestory ,onCreateView 和 onDestroyView等

谈一谈单例模式,建造者模式,工厂模式的使用场景?如何合理选择?

参考答案:

  1. 单例模式:保证全局只有一个实例,如网络请求
  2. 建造者模式:用于需要设置比较多的属性可以用直接链式,如AlerDialog
  3. 工厂模式:用于业务的实体类创建,易于扩展,如BitMapFactory

中等

view的绘制流程
MVC、MVP、MVVM

(1) MVC,Model View Controller,是软件架构中最常见的一种框架,简单来说就是通过 controller 的控制去操作 model 层的数据,并且返回给 view 层展示。当用户发出事件的时候,view 层会发送指令到 controller 层,接着 controller 去通知 model 层更新数据,model 层更新完数据以后直接显示在 view 层上,这就是 MVC 的工作原理。

(2) MVP 是 MVC 的演化。MVP 的 model 层相对于 MVC 是一样的,而 activity 和 fragment 不再是 controller 层,而是纯粹的 view 层,所有关于用户事件的转发全部交由 presenter 层处理。presenter 层充当了桥梁的作用,用于操作 view 层发出的事件传递到 presenter 层中,presenter 层去操作 model 层,并且将数据返回给 view 层。

(3) MVVM 和 MVP 的区别貌似不大,只不过是 presenter 层换成了 viewmodel 层,还有一点就是 view 层和 viewmodel 层是相互绑定的关系,这意味着当你更新 viewmodel 层的数据的时候,view 层会相应的变动 ui。

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

(1) IntentService 继承自 Service。由于 Service 运行在主线程,无法进行耗时操作。所以你需要在 Service 中开启一个子线程,并且在子线程中运行。为了简化这一操作,Android 中提供了 IntentService 来进行这一处理。通过查看 IntentService 的源码可以看到,在 onCreate 中,我们开启了一个 HandlerThread 线程,之后获取 HandlerThread 线程中的 Looper,并通过这个 Looper 创建了一个 Handler。然后在 onStart 方法中通过这个 Handler 将 intent 与 startId 作为 Message 的参数进行发送到消息队列中,然后交由 Handler 中的 handleMessage 中进行处理。由于在 onStart 方法是在主线程内运行的,而 Handler 是通过工作者线程 HandlerThread 中的 Looper 创建的。所以也就是在主线程中发送消息,在工作者接收到消息后便可以进行一些耗时的操作。

(2) 进程间通信

Activity、View 和 Window 三者的关系?

参考答案:

首先先说下 Window:

Window 表示窗口,是个抽象的概念,每个 Window 都对应着一个 View 和一个 ViewRootImpl,Window 通过 ViewRootImpl 和 View 建立联系,因此 Window 并不是实际存在的,他是以 View 的形式存在的。也就是说 View 才是 Window 存在的实体。实际使用中无法直接访问 Window,对 Window 的访问必须通过 WindowManager。

再说 View:

View 是 Android 中视图的呈现方式,但是 View 不能单独存在,它必须附着在 Window 这个抽象的概念上,因此有视图的地方就有 Window。

最后 Activity:

Android 中的四大组件之一 Activity 就是用来显示视图的,因此一个 Activity 就对应着一个 Window,不止 Activity,其实 Dialog,Toast,PopUpWindow,菜单等都对应着一个 Window。

Activity,View,Window 相关连的具体实现:

在 Activity 启动时 通过 attach 方法,创建 Window 的实例即 PhoneWindow 然后绑定 Activity,Activity 实现了 Window 的 Callback 等接口,当 Window 接收到外界的状态改变时就会回调给 Activity,比如 onAttachToWindow、onDetacheFromWindow、dispatchTouchEvent 等。 PhoneWindow 初始化时会创建 DecorView (也就是顶级 View),然后初始化 DecorView 的结构,加载布局文件到 DecorView,之后再将 Activity 的视图添加到 DecorView 的 mContentParent 中。

总结:

Activity 通过 Window 完成对视图 View 的管理,一个 Activity 对应一个 Window,每个 Window 又对应一个 View。

说说项目中用到的设计模式和使用场景?

单例模式

常见应用场景:网络请求的工具类、sp存储的工具类、弹窗的工具类等

工厂模式

常见应用场景:activity的基类等

责任链模式

常见应用场景:OKhttp的拦截器封装

观察者模式

常见应用场景:Rxjava的运用

代理模式

常见应用场景:AIDL的使用

建造者模式

常见应用场景:Dialog的创建

Android 中消息机制和原理?

参考答案:

首先在主线程创建一个 Handler 对象 ,并重写 handleMessage() 方法。然后当在子线程中需要进行更新UI的操作,我们就创建一个 Message 对象,并通过 Handler 发送这条消息出去。

之后这条消息被加入到 MessageQueue 队列中等待被处理,通过 Looper 对象会一直尝试从 Message Queue 中取出待处理的消息,最后分发回 Handler 的 handleMessage() 方法中。

Window 和 DecorView 是什么?DecorView 又是如何和 Window 建立联系的?

参考答案:

Window 是 WindowManager 最顶层的视图,它负责背景(窗口背景)、Title之类的标准的UI元素,Window 是一个抽象类,整个Android系统中, PhoneWindow是 Window 的唯一实现类。至于 DecorView,它是一个顶级 View,内部会包含一个竖直方向的LinearLayout,这个 LinearLayout 有上下两部分,分为 titlebar 和 contentParent 两个子元素,contentParent 的 id 是 content,而我们自定义的 Activity 的布局就是 contentParent 里面的一个子元素。View 层的所有事件都要先经过 DecorView 后才传递给我们的 View。 DecorView 是 Window 的一个变量,即 DecorView 作为一切视图的根布局,被 Window 所持有,我们自定义的 View 会被添加到 DecorView ,而DecorView 又会被添加到 Window 中加载和渲染显示

什么是 AIDL?它的使用场景是什么?

参考答案:

AIDL:AIDL是用于进程间的通迅 能够实现进程间的一对多实时并发通迅 通过定义AIDL接口 创建一个服务将接口暴露给客服端 客户端把定义的ALDL文件复制到项目中 通过bindService绑定服务端服务 并通过 定义AIDL.Stub.asInterface(service)将服务端返回的Binder代理对象转换成AIDL接口所属的类型 调用方法即可

webp 和 svg 格式的图片各自有什么特点?应该如何在 Android 中使用?

参考答案:

一、svg格式 svg是矢量图,这意味着svg图片由直线和曲线以及绘制它们的方法组成。当你放大一个svg图片的时候,你看到的还是线和曲线,而不会出现像素点。svg图片在放大时,不会失真,所以它非常适合用来绘制企业Logo、Icon SVG格式特点:

1、SVG 指可伸缩矢量图形 (Scalable Vector Graphics)

2、SVG 用来定义用于网络的基于矢量的图形

3、SVG 使用 XML 格式定义图形

4、SVG 图像在放大或改变尺寸的情况下其图形质量不会有所损失

5、SVG 是万维网联盟的标准

6、SVG 与诸如 DOM和 XSL 之类的W3C标准是一个整体

二、webp格式 webp是谷歌开发的一种新图片格式,是同时支持有损和无损压缩的、使用直接色的、点阵图。

Android性能优化?

参考答案:

  • 启动优化: application中不要做大量耗时操作,如果必须的话,建议异步做耗时操作
  • 布局优化:使用合理的控件选择,少嵌套。(合理使用include,merge,viewStub等使用)
  • apk优化(资源文件优化,代码优化,lint检查,合理使用shape替代图片,webp等)
  • 性能优化,网络优化,电量优化
    • 避免轮询,尽量使用推送。
    • 应用处于后台时,禁用某些数据传输
    • 限制访问频率,失败后不要无限重连
    • 选用合适的定位服务(GPS定位,网络定位,被动定位)
    • 使用缓存
    • startActivityForResult替代发送广播
  • 内存优化
    • 循环尽量不使用局部变量
    • 避免在onDraw中创建对象,onDraw会被频繁调用,容易造成内存抖动。循环中创建大的对象,也是如此。
    • 不用的对象及时释放
    • 数据库的cursor及时关闭
    • adapter使用缓存
    • 注册广播后,在生命周期结束时反注册
    • 及时关闭流操作
    • 图片尽量使用软引用,较大的图片可以通过bitmapFactory缩放后再使用,并及时recycler。另外加载巨图时不要 使用setImageBitmap或setImageResourse或BitmapFactory.decodeResource,这些方法拿到的都是bitmap的对象,占用内存较大。可以用BitmapFactory.decodeStream方法配合BitmapFactory.Options进行缩放
    • 避免static成员变量引用资源耗费过多实例
    • 避免静态内部类的引用

Android 内存泄漏

内存泄漏简单地说就是申请了一块内存空间,使用完毕后没有释放掉。它的一般表现方式是程序运行时间越长,占用内存越多,最终用尽全部内存,整个系统崩溃。由程序申请的一块内存,且没有任何一个指针指向它,那么这块内存就泄露了。

  1. 资源对象没关闭造成的内存泄漏(如: Cursor、File等)
  2. Bitmap 对象不在使用时调用recycle()释放内存
  3. 集合中对象没清理造成的内存泄漏(特别是 static 修饰的集合)
  4. 接收器、监听器注册没取消造成的内存泄漏
  5. Activity 的 Context 造成的泄漏,可以使用 ApplicationContext
  6. Handler 造成的内存泄漏问题(一般由于 Handler 生命周期比其外部类的生命周期长引起的)
对于 Context,你了解多少
  1. 在 Android 平台上 , Context 是一个基本的概念,它在逻辑上表示一个运行期的“上下文”
  2. Context 体现到代码上来说,是个抽象类,其主要表达的行为有:使用系统提供的服务、访问资源 、信息 存储相关以及AMS的交互
  3. 在 Android 平台上,Activity、Service 和 Application 在本质上都是个 Context
  4. Android 中上下文访问应用资源或系统服务的动作都被统一封装进 ContextImpl 类中.Activity、 Service、Application 内部都含有自己的 ContextImpl,每当自己需要访问应用资源或系统服务时,就是 把请求委托给内部的 ContextImpl
  5. ContextWrapper 为 Context 的包装类, 它在做和上下文相关的动作时,基本上都是委托给 ContextImpl 去做
  6. ContextImpl 为一个上下文的核心部件,其负责和Android平台进行通信. 就以启动 activity 动作来说,最后 会走到 ContextImpl 的 startActivity(),而这个函数内部大体上是进一步调用 mMainThread.getInstrumentation().execStartActivity(),从而将语义发送给Android系统
  7. Context数量 = Activity数量 + Service数量 + 1 上面的1表示 Application 数量,一个应用程序里面可以有多个 Application,可是在配置文件 AndroidManifest.xml中只能注册一个, 只有注册的这个 Application 才是真正的 Application
简述一下 Android 中 UI 的刷新机制?

参考答案:

界面刷新的本质流程

通过ViewRootImpl的scheduleTraversals()进行界面的三大流程。调用到scheduleTraversals()时不会立即执行,而是将该操作保存到待执行队列中。并给底层的刷新信号注册监听。当VSYNC信号到来时,会从待执行队列中取出对应的scheduleTraversals()操作,并将其加入到主线程的消息队列中。主线程从消息队列中取出并执行三大流程: onMeasure()-onLayout()-onDraw()

同步屏障的作用

同步屏障用于阻塞住所有的同步消息(底层VSYNC的回调onVsync方法提交的消息是异步消息)用于保证界面刷新功能的performTraversals()的优先执行。

同步屏障的原理?

主线程的Looper会一直循环调用MessageQueue的next方法并且取出队列头部的Message执行,遇到同步屏障(一种特殊消息)后会去寻找异步消息执行。如果没有找到异步消息就会一直阻塞下去,除非将同步屏障取出,否则永远不会执行同步消息。界面刷新操作是异步消息,具有最高优先级我们发送的消息是同步消息,再多耗时操作也不会影响UI的刷新操作

什么是同步屏障?

参考答案:

handler.getLooper().getQueue().postSyncBarrier()加入同步屏障后,Message.obtain()获取一个target为null的msg,并根据当前时间将该msg插入到链表中。 在Looper.loop()循环取消息中 Message msg = queue.next(); target为空时,取链表中的异步消息。 通过setAsynchronous(true)来指定为异步消息

应用场景:ViewRootImpl scheduleTraversals中加入同步屏障 并在view的绘制流程中post异步消息,保证view的绘制消息优先执行

ANR 出现的场景以及解决方案?

参考答案:

场景: 1、触摸无响应5s 2、BroadCastReciver 前台处理超过10s 后台超过60s 3、Server 前台处理超过20s 后台超过200s

ANR出现的类型有两种 1、主线程耗时导致 2、CPU、内存、IO 占用过高资源耗尽(其他进程也可以导致)

如何避免: 1、不要在主线程中做耗时的操作 2、避免CPU占用过高,简化方法,减少执行时间 3、避免内存占用过高,防止内存泄漏

谈谈代码混淆的步骤?

参考答案:

代码混淆的目的: 1、代码混淆之后会随机生成难易理解的类名、方法名以及属性名,加大反编译的难度; 2、可以对apk进行优化,缩小包的体积;

代码混淆的步骤: 1、在gradle文件里面打开配置:minifyEnabled true; 2、在proguard-rules.pro 文件里面配置混淆规则; 在配置混淆的时候,需要注意:1、四大组件以及view可以不进行混淆;2、实体类不进行混淆;3、第三方库根据各自的要求配置混淆规则;

Android 中进程间通信有哪些方式?

通信方式

优点

缺点

使用场景

Bundle

简单易用

只能传输Bundle支持的数据类型

四大组件间的进程间通信

文件共享

简单易用

不适合高并发场景,并且无法做到即时通信

无并发访问的情况,交换实时性不高的简单数据

Messenger

功能一般,支持一对多串行通信,支持实时通信

不能很好的处理高并发情况,不支持RPC,只能传输Bundle支持的数据类型

低并发的一对多即时通信,无RPC需求,或无须返回结果的RPC需求

AIDL

功能强大,支持一对多并发和实时通信

使用复杂,需要处理好线程同步问题

一对多通信且有RPC需求

ContentProvider

在数据源访问方面功能强大,支持一对多并发数据共享,可通过call方法扩展其他操作

可理解为受约束的AIDL,主要提供数据源的CRUD操作

一对多的进程间数据共享

Socket

功能强大,可通过网络传输字节流,支持一对多并发实时通信

实现细节较为烦琐,不支持直接RPC

网络数据交换

什么是 JNI?具体说说如何实现 Java 与 C++ 的互调?

参考答案:

  • 在Java类中声明native方法
  • 使用javac命令将Java类生成class文件
  • 使用javah文件生成头文件
  • 编写cpp文件实现jni方法
  • 生成so库 到此为止,java就可以通过调用native方法调用c++函数了,对于在c++中调用java方法,
  • 通过完整类名获取jclass
  • 根据方法签名和名称获取构造方法id
  • 创建对象(如果要调用的是静态方法则不需要创建对象)
  • 获取对象某方法id
  • 通过JNIEnv根据返回值类型、是否是静态方法调用对应函数即可
如何绕过 Android 9.0 针对反射的限制?

参考答案:

双重反射,即利用反射调用反射API,这个时候系统进行栈回溯,发现直接调用者是反射API,反射API也是系统API,就直接通过了

SurfaceView

非常难

jvm虚拟机
请简要谈一谈 Java 中的垃圾回收机制?

垃圾回收机制: 当堆内存中的某块区域没有对象引用时,这个内存区域就会变成垃圾,等待垃圾回收器的回收,

强制垃圾回收: 程序只能控制一个对象不被任何引用变量引用,绝对不能控制它的回收。 System.gc(); Runntime.getTuntime().gc(); 上面两个方法会建议系统进行垃圾回收,但是系统也有可能不进行回收。 对象的复活可以通过 finalize()方法来实现

简述 JVM 中类的加载机制与加载过程?

Java语言系统自带有三个类加载器:

  • Bootstrap ClassLoader 最顶层的加载类,主要加载核心类库,%JRE_HOME%\lib下的rt.jar、 resources.jar、charsets.jar和class等。另外需要注意的是可以通过启动jvm时指定-Xbootclasspath和路径来改变Bootstrap ClassLoader的加载目录。比如java -Xbootclasspath/a:path被指定的文件追加到默认的bootstrap路径中。
  • Extention ClassLoader 扩展的类加载器,加载目录%JRE_HOME%\lib\ext目录下的jar包和class文件。还 可以加载-D java.ext.dirs选项指定的目录。
  • Appclass Loader也称为SystemAppClass 加载当前应用的classpath的所有类。

我们需要知道这三个加载器的加载顺序

  1. Bootstrap CLassloder
  2. Extention ClassLoader
  3. AppClassLoader

然后需要知道这个加载顺序具体执行策略 双亲委托机制

一个类加载器查找class和resource时,是通过“委托模式”进行的,它首先判断这个class是不是已经加载成功,如果没有的话它并不是自己进行查找,而是先通过父加载器,然后递归下去,直到Bootstrap ClassLoader,如果Bootstrap classloader找到了,直接返回,如果没有找到,则一级一级返回,最后到达自身去查找这些对象。这种机制就叫做双亲委托。

JVM、Dalvik、ART 三者的原理和区别

1、JVM指Java虚拟机,能够运行Java字节码的虚拟机器,有多种实现

2、Dalvik虚拟机是Google设计用于Android平台的虚拟机,支持已转换为.dex格式的Java程序的运行。与JVM的区别:

  • Dalvik基于寄存器,JVM基于堆栈
  • Dalvik有自己的字节码,不使用Java字节码
  • Android2.2开始,Dalvik支持JIT即时编译

3、ART虚拟机是现行的Android虚拟机,与Dalvik的区别:

  • ART采用的是Ahead-of-time AOT预编译技术,Dalvik采用的是JIT即时编译技术
  • AOT预编译会在应用安装过程中,将所有的字节码编译成机器码,应用运行时无需实时编译了,直接调用即可
  • JIT即时编译在应用启动时,通过性能分析来优化代码的执行;在应用运行时,实时将字节码编译成机器码

所以,ART虚拟机提高了程序的运行效率;首次安装需要预编译,所以安装时间比Dalvik中略长,机器码占用空间大,应用占用空间也会略大。

说说 Activity 加载的流程

App 启动流程(基于Android8.0):

  • 点击桌面 App 图标,Launcher 进程采用 Binder IPC(具体为ActivityManager.getService 获取 AMS 实例) 向 system_server 的 AMS 发起 startActivity 请求
  • system_server 进程收到请求后,向 Zygote 进程发送创建进程的请求;
  • Zygote 进程 fork 出新的子进程,即 App 进程
  • App 进程创建即初始化 ActivityThread,然后通过 Binder IPC 向 system_server 进程的 AMS 发起 attachApplication 请求
  • system_server 进程的 AMS 在收到 attachApplication 请求后,做一系列操作后,通知 ApplicationThread bindApplication,然后发送 H.BIND_APPLICATION 消息
  • 主线程收到 H.BIND_APPLICATION 消息,调用 handleBindApplication 处理后做一系列的初始化操作,初始化 Application 等
  • system_server 进程的 AMS 在 bindApplication 后,会调用 ActivityStackSupervisor.attachApplicationLocked,之后经过一系列操作,在 realStartActivityLocked 方法通过 Binder IPC 向 App 进程发送 scheduleLaunchActivity 请求;
  • App进程的 binder 线程(ApplicationThread)在收到请求后,通过 handler 向主线程发送 LAUNCH_ACTIVITY 消息;
  • 主线程收到 message 后经过 handleLaunchActivity,performLaunchActivity 方法,然后通过反射机制创建目标 Activity;
  • 通过 Activity attach 方法创建 window 并且和 Activity 关联,然后设置 WindowManager 用来管理 window,然后通知 Activity 已创建,即调用 onCreate
  • 然后调用 handleResumeActivity,Activity 可见

补充:

  • ActivityManagerService 是一个注册到 SystemServer 进程并实现了 IActivityManager 的 Binder,可以通过 ActivityManager 的 getService 方法获取 AMS 的代理对象,进而调用 AMS 方法
  • ApplicationThread 是 ActivityThread 的内部类,是一个实现了 IApplicationThread 的 Binder。AMS通过 Binder IPC 经 ApplicationThread 对应用进行控制
  • 普通的 Activity 启动和本流程差不多,至少不需要再创建 App 进程了
  • Activity A 启动 Activity B,A 先 pause 然后 B 才能 resume,因此在 onPause 中不能做耗时操作,不然会影响下一个 Activity 的启动
View.post() 为什么可以获取到宽高信息?

参考答案:

View.post方法调用时,如果在 View 还没开始绘制时( Activity 的 onResume方法还没回调之前 或者onResume方法执行了,但是 ViewRootImpl 的 performTraversals 还没开始执行)就会用一个初始长度为 4 的数组缓存起来(Runnable 数量大于4时会进行扩容),ViewRootImpl 在初始化时创建了一个 View.AttchInfo 对象并绑定 ViewRootImpl 的 Handler ,该 Handler 也用于发送 View 绘制相关的 msg ;

等到 ViewRootImpl执行 performTraversals方法时(此时 Activity 已经回调了onResume),会配置 View 的 AttchInfo 对象并且通过 View 的 dispatchAttachedToWindow 方法传入到 View 里面完成绑定,在该方法中会取出 View 缓存的 Runnable 并用 View.AttchInfo 的 Handler 来进行 post 方法,这样子就会加入到 MessageQueue 里面进行排队,等到这些缓存 Runnable 执行时,主线程里面 View的绘制流程也就结束了,所以这时候 Looper 取出这些缓存的Runnable 执行时就可以拿到 View 的宽高

那么,什么情况下View.post 方法不会执行呢?如果 Activity 因为某些原因没有执行到 onResume 的话,无法顺利调用 ViewRootImpl 的 performTraversals 的话,View.post 方法就不会执行

提醒:如果 View 是 new 出来的,并且没有通过 addView 等方法依赖到 DecorView 上面,它的 post 方法也是不会执行的,因为它没有机会和 ViewRootImpl 进行互动了

Binder机制:

1.为了保证进程空间不被其他进程破坏或干扰,Linux中的进程是相互独立或相互隔离的。

2.进程空间分为用户空间和内核空间。用户空间不可以进行数据交互;内核空间可以进行数据交互,所有进程共用一个内核空间。

3.Binder机制相对于Linux内传统的进程间通信方式:

  • (1)性能更好;Binder机制只需要拷贝数据一次,管道、消息队列、Socket等都需要拷贝数据两次;而共享内存虽然不需要拷贝,但实现复杂度高。
  • (2)安全性更高;Binder机制通过UID/PID在内核空间添加了身份标识,安全性更高。

4.Binder跨进程通信机制:基于C/S架构,由Client、Server、Server Manager和Binder驱动组成。

5.Binder驱动实现的原理:通过内存映射,即系统调用了mmap()函数。

6.Server Manager的作用:管理Service的注册和查询。

7.Binder驱动的作用:

(1)传递进程间的数据,通过系统调用mmap()函数;

(2)实现线程的控制,通过Binder驱动的线程池,并由Binder驱动自身进行管理。

8.Server进程会创建很多线程处理Binder请求,这些线程采用Binder驱动的线程池,由Binder驱动自身进行管理。一个进程的Binder线程池默认最大是16个,超过的请求会阻塞等待空闲的线程。

9.Android中进行进程间通信主要通过Binder类(已经实现了IBinder接口),即具备了跨进程通信的能力。

谈谈安卓 Apk 构建的流程?

参考答案:

1) aapt 为res 目录下资源生成R.java 文件,同时为AndroidMainfest.xml 生成Mainfeset.java文件

2)aidl 将项目中自定义的aidl 生成相应的Java文件

3) javac 将项目中所有java 代码编译成class 文件,包括 业务逻辑代码, aapt 生成 java文件,aidl 生成java 文件

4) proguard , 混淆同时生成mapping.txt ,这步可选

5) 将所有class 文件(包括第三方class 文件) 转换为dex 文件

6)aapt 打包, 将res资源,assets资源,打包成一个.ap的文件

7)apkbuilder ,将所有dex 文件,.ap文件, AndroidMainfest.xml打包为.apk 文件,这是一个未签名的apk包 8)jarsigner 对apk 进行签名

9)ziplign 对apk 进行对齐操作,以便运行时节约内存。

简述下热修复的原理?

参考答案: 热修复分为三个部分,分别是Java代码部分热修复,Native代码部分热修复,还有资源热修复。

资源部分热更新直接反射更改所有保存的AssetManager和Resources对象就行(可能需要重启应用)

Native代码部分也很简单,系统找到一个so文件的路径是根据ClassLoader找的,修改ClassLoader里保存的路径就行(可能需要重启应用)

Java部分的话目前主流有两种方式,一种是Java派,一种是Native派。

  • java派:通过修改ClassLoader来让系统优先加载补丁包里的类 代表作有腾讯的tinker,谷歌官方的Instant Run,包括multidex也是采用的这种方案 优点是稳定性较好,缺点是可能需要重启应用
  • native派:通过内存操作实现,比如方法替换等 代表作是阿里的SopHix,如果算上hook框架的话,还有dexposed,epic等等 优点是即时生效无需重启,缺点是稳定性不好: 如果采用方法替换方式实现,假如这个方法被内联/Sharpening优化了,那么就失效了;inline hook则无法修改超短方法。 热修复后使用反射调用对应方法时可能发生IllegalArgumentException。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/2827.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

cursor重构谷粒商城02——30分钟构建图书管理系统【cursor使用教程番外篇】

前言:这个系列将使用最前沿的cursor作为辅助编程工具,来快速开发一些基础的编程项目。目的是为了在真实项目中,帮助初级程序员快速进阶,以最快的速度,效率,快速进阶到中高阶程序员。 本项目将基于谷粒商城…

[Qualcomm]Qualcomm MDM9607 SDK代码下载操作说明

登录Qualcomm CreatePoing Qualcomm CreatePointhttps://createpoint.qti.qua

【15】Word:互联网发展状况❗

目录 题目​ NO2 NO3 NO4 NO5 NO6 NO7.8.9 NO7 NO8 NO9 NO10 题目 NO2 布局→页面设置→纸张:A4→页边距:上下左右→版式:页眉/页脚页码范围:多页:对称页边距→内侧/外侧→装订线 NO3 首先为文档应用内置…

ROS1学习记录

我使用的是ubuntu20.04下的ROS Noetic版本,是ROS 1 的最后一个长期支持(LTS)版本,将于2025年5月停止维护 一,Linux系统基本操作 ctrlaltt快速打开终端 1,pwd命令 查看当前终端所在路径 使用方式&#…

Go Ebiten小游戏开发:贪吃蛇

贪吃蛇是一款经典的小游戏,玩法简单却充满乐趣。本文将介绍如何使用 Go 语言和 Ebiten 游戏引擎开发一个简单的贪吃蛇游戏。通过这个项目,你可以学习到游戏开发的基本流程、Ebiten 的使用方法以及如何用 Go 实现游戏逻辑。 项目简介 贪吃蛇的核心玩法是…

ASP.NET Core - .NET 6 以上版本的入口文件

ASP.NET Core - .NET 6 以上版本的入口文件 自从.NET 6 开始,微软对应用的入口文件进行了调整,移除了 Main 方法和 Startup 文件,使用顶级语句的写法,将应用初始化的相关配置和操作全部集中在 Program.cs 文件中,如下&…

Chapter1:初见C#

参考书籍:《C#边做边学》; 1.初见C# 1.1 C#简介 C # {\rm C\#} C#编写了许多完成常用功能的程序放在系统中,把系统中包含的内容按功能分成多个部分,每部分放在一个命名空间中,导入命名空间语法格式如下: /…

React封装倒计时按钮

背景 在开发过程中,经常需要使用到倒计时的场景,当用户点击后,按钮进行倒计时,然后等待邮件或者短信发送,每次都写重复代码,会让代码显得臃肿,所以封装一个组件来减少耦合 创建一个倒计时组件…

【编译构建】用cmake编译libjpeg动态库并实现转灰度图片

先编译出libjepg动态库 1、下载libjpeg源码: https://github.com/libjpeg-turbo/libjpeg-turbo 2、编译出动态库或静态库 写一个编译脚本,用cmake构建。 #!/bin/bash# 定义变量 SOURCE_DIR"/home/user/libjpeg-turbo-main" BUILD_DIR"${SOURCE_…

ORB-SLAM2源码学习: Frame.cc: cv::Mat Frame::UnprojectStereo将某个特征点反投影到三维世界坐标系中

前言 这个函数是在跟踪线程中更新上一帧的函数中被调用。 1.函数声明 cv::Mat Frame::UnprojectStereo(const int &i) 2.函数定义 1.获取这个特征点的深度值。 const float z mvDepth[i];深度值由双目或 RGB-D 传感器获取。 在双目情况下,这个深度来自…

单片机存储器和C程序编译过程

1、 单片机存储器 只读存储器不是并列关系,是从ROM发展到FLASH的过程 RAM ROM 随机存储器 只读存储器 CPU直接存储和访问 只读可访问不可写 临时存数据,存的是CPU正在使用的数据 永久存数据,存的是操作系统启动程序或指令 断电易失 …

【Excel】【VBA】双列排序:坐标从Y从大到小排列之后相同Y坐标的行再对X从小到大排列

Excel VBA 双列排序 功能概述 这段VBA代码实现了Excel中的双列排序功能,具体是: 跳过前3行表头先按C列数据从大到小排序在C列值相同的情况下,按B列从大到小排序排序时保持整行数据的完整性 流程图 #mermaid-svg-XJERemQluZlM4K8l {font-fa…

【25考研】西南交通大学软件工程复试攻略!

一、复试内容 复试对考生的既往学业情况、外语听说交流能力、专业素质和科研创新能力,以及综合素质和一贯表现等进行全面考查,主要考核内容包括思想政治素质和道德品质、外语听说能力、专业素质和能力,综合素质及能力。考核由上机考试和面试两部分组成&a…

运行fastGPT 第四步 配置ONE API 添加模型

上次已经装好了所有的依赖和程序。 下面在网页中配置One API ,这个是大模型的接口。配置好了之后,就可以配置fastGPT了。 打开 OneAPI 页面 添加模型 这里要添加具体的付费模型的API接口填进来。 可以通过ip:3001访问OneAPI后台,**默认账号…

硬件知识:显示器发展历程介绍

目录 一、阴极射线管显示器(CRT) 二、等离子显示器(PDP) 三、液晶显示器(LCD) 四、传统LED显示器(LED) 五、有机发光二极管显示器(OLED) 六、量子点显示器(QD) 七、MiniLED显示器(MiniLED) 八、MicroLED显示器(MicroLED) 总结 显示器作为电子设备与人…

修复5.0.0r 64位版本浏览器和一些库找不到的问题

笔者在使用5.0.0r版本64位时踩过不少坑,先将相关修复方法分享 浏览器无法使用 base/startup/appspawn/appdata-sandbox64.json添加沙箱配置 相关修复pr:https://gitee.com/openharmony/startup_appspawn/pulls/1854/files {"src-path" : "/system…

【Flink系列】4. Flink运行时架构

4. Flink运行时架构 4.1 系统架构 Flink运行时架构——Standalone会话模式为例 1)作业管理器(JobManager) JobManager是一个Flink集群中任务管理和调度的核心,是控制应用执行的主进程。也就是说,每个应用都应该被…

IP层之分片包的整合处理

前言 在上一章节中,笔者就IP层的接收代码逻辑做了简单介绍,并对实现代码进行了逻辑梳理以及仿真测试,并且在上一章节中,就IP层的分片包问题,如何确定分片包是否存在已经进行了简单介绍,并在接收模块中&…

使用jupyter notebook没有正常打开浏览器的几种情况解决

迅速记录前期 1.下载 https://www.anaconda.com/products/individual 2.安装 直接默认安装就行 3.打开jupyter notebook 在开始菜单里面可以找到 4.遇到的问题解决 1.运行jupyter notebook,黑窗口自动关了 每次黑窗口迅速的加载完就自己关掉了 也没有打开新…

50.【8】BUUCTF WEB HardSql

进入靶场 随便输输 上order by ????????,被过滤了,继续找其他也被过滤的关键字 #,-- -,-- 都不行,尝试其他特殊字符后发现and,union,select,空格,都被过滤了 如下 我就不知…