另外,最初,在项目的某些模块出现延迟后,我们使用系统工具对延迟进行优化,同时检查延迟期间CPU的状态。这个模块结合代码进行了重构,部分代码进行了异步和延迟,解决了项目前期的问题。然而,随着项目的发展,离线滞后问题也随之增加。与此同时,我们开始寻找在线滞后反馈,因为很难在离线状态下重现在线滞后反馈。这个想法来自于Android的消息处理机制,主线程执行的代码会返回到Looper.loop方法,其中每条消息内部都包含一个mLogging对象。利用这个预处理机会来实施自动化监控解决方案。同时,我们现阶段还完善了在线ANR报告。我们采取的方法是监控ANR信息,并与ANR-WatchDog结合起来,作为无文件权限的高版本的辅助解决方案。完成这个后期检测解决方案后,我们还搭建了在线监控工具和离线检测工具,最终实现了一整套全面、多维度的解决方案。
1.9 如何自动检索延误信息?
我们的想法来自Android的消息处理机制,一旦主线程执行完代码,就会转移到Looper.loop方法。该函数有一个mLogging 对象,在处理每条消息之前和之后都会调用该对象。主线程移动到Looper.loop方法。如果您的线程卡住,您可以在执行此消息之前在子线程中postDelayed 任何耗时的代码。您设定的阈值。如果主线程的消息在此阈值内完成,则子线程的任务将被取消。可以获取主线程当前正在执行的堆栈,知道哪里发生了卡顿。
经过实践,我发现用这种方案得到的堆栈信息并不总是准确的。因为你得到的堆栈信息很可能就是主线程的最终执行位置,而这就是它实际花费时间的地方。我们对这个方案做了一些优化。这意味着在一个周期内多次收集主线程的堆栈信息。如果出现滞后,请将其收集起来。暂停信息被压缩并报告给APM后端以检测重复的堆栈信息。这些重复堆栈很可能发生暂停,从而提高检索暂停信息的准确性。
1.10 为什么TextView上的setText需要这么长的时间?你了解TextView绘图层的源码吗?
1.11 移动终端获取网络数据优化的几点
1.连接复用:节省连接建立时间,例如通过开启keepalives。在Android 上,默认情况下为HttpURLConnection 和HttpClient 启用keepalive。 2.2 之前的HttpURLConnection 有一个影响连接池的错误。
2. 合并请求:即将多个请求合并为一个请求。更常见的是网页中的CSS 图像精灵。如果对某个特定页面的请求过多,也可以考虑合并特定请求。
3. 减少请求数据的大小。对于post 请求,您可以gzip 正文并压缩标头(但仅支持http 2.0)。
返回数据的body也可以进行gzip压缩,将body数据量减少到原来大小的30%左右(特别是格式不同的情况下)(虽然返回的数据不会有太大变化,但支付宝聊天使用。返回的数据)。
4、根据用户当前的网络质量来决定下载哪种质量的照片(常用于电商)。
5、使用HttpDNS优化DNS:DNS存在解析慢、DNS劫持等问题。尽管DNS 支持TCP 和UDP,但大多数标准DNS 都基于UDP,并与DNS 服务器上的端口53 进行交互。 HTTPDNS,顾名思义,使用HTTP 协议与DNS 服务器的80 端口进行通信。由于不采用传统的DNS解析,绕过运营商的LocalDNS服务器,有效防止域名劫持,提高域名解析效率。
1.12 网络优化请参考百度APP网络优化。
网络优化最佳实践!百度应用网络深度优化系列《一》 DNS优化
网络优化最佳实践!百度应用网络深度优化系列《二》 连接优化
网络优化最佳实践!百度App网络详细优化系列《三》 弱网优化
1.13APP安全优化
1. 如何提高应用程序的安全性?
2. 如何增强Android应用程序?
3、Android混淆原理是什么?
4.谈谈对Android签名的理解。
1.14 为什么我的WebView加载缓慢?
这是因为客户端在加载H5页面之前必须初始化WebView,后续的界面加载过程会被阻塞,直到WebView完全初始化。
优化方法主要关注两点:
预加载WebView。
WebView加载时请求H5页面数据。
常见的方法包括:
全球网络视图。
客户端代理页面请求。 WebView初始化后,向客户端请求数据。
资产商店离线包。
此外,还有其他几种优化方法。
如果您的脚本运行缓慢,您可以在最后运行它,而不会阻塞页面解析。
DNS 链接速度较慢,允许客户端重复使用域名和链接。
React 框架代码运行缓慢。这部分代码可以提前拆分分析。
1.15 如何优化自定义视图
为了使您的视图更快,您应该尽量减少频繁调用的方法中不必要的代码。我们先从onDraw开始。您需要特别小心,不要在这里进行任何内存分配。这是因为GC发生并且发生延迟。在初始化或动画间隙期间分配内存。动画运行时不要分配内存。
您还应该尽可能少地调用onDraw。 onDraw通常是由调用invalidate()引起的,因此尽量减少invalidate()调用的次数。如果可能,请调用带四个参数的validate() 方法,而不是不带参数的validate() 方法。不带参数的无效会强制重绘整个视图。
另一个非常耗时的操作是请求布局。每次执行requestLayout() 时,Android UI 系统都会遍历整个视图层次结构并计算每个视图的大小。如果发现不一致的值,则必须重新计算多次。此外,您应该使视图层次结构尽可能平坦。这对于提高效率非常有帮助。
如果您有复杂的UI,您应该考虑创建自定义ViewGroup 来执行布局操作。与内置视图不同,自定义视图允许程序仅测量这部分,从而无需遍历整个视图层次结构来计算大小。
1.16 分析TraceView的实现原理以及数据错误的原因。
Android性能优化跟踪视图
2.Android Framework相关
2.1View的事件传递机制是什么?如何解决滑动冲突?
触摸事件对应于MotionEvent类。事件主要分为三种类型:
行动向下
ACTION_MOVE(移动距离超过一定阈值则判定为ACTION_MOVE操作)
ACTION_UP
View事件传递的本质就是传递MotionEvent事件的过程。换句话说,当MotionEvent发生时,系统会将点击事件传递给特定的View。
事件交付流程
事件分发过程通过三种方式完成:
如果dispatchTouchEvent:方法返回true,则意味着该事件将被当前视图消耗。返回super.dispatchTouchEvent 意味着事件将继续分发。返回false 意味着事件将被传递。父类的onTouchEvent 来处理。
onInterceptTouchEvent:该方法返回true表示该事件将被拦截并传递给自己的onTouchEvent方法进行消费。如果返回false,则表示该事件没有被拦截,应该继续传递给子视图。返回super.onInterceptTouchEvent(ev)时,事件拦截分为两种情况:
1、如果某个视图有子视图,点击该子视图,子视图不会被拦截,继续发送。
由子视图处理。这与返回false 相同。
2、如果视图没有子视图,或者有子视图但是子视图没有被点击(此时ViewGroup
(相当于常规View),View的onTouchEvent会响应。这相当于返回true。
注意:常见的LinearLayout、RelativeLayout、FrameLayout等ViewGroup默认是不拦截的,但是
根据具体情况,ScrollView、ListView等ViewGroup可能会拦截。
onTouchEvent:方法返回值为true表示当前视图可以处理相应的事件。返回值为false 表示当前视图无法处理该事件,会传递给父视图的onTouchEvent 方法进行处理。返回super.onTouchEvent(ev)时,事件处理可以分为两种情况。
1. 如果视图可点击或可长点击,则返回true 表示消耗。
返回事件与返回true 相同。
2. 如果视图不可点击或不可长时间点击,则返回false 表示否则。
消费这个事件是向上传递的,和返回false一样。
注意:Android 系统具有三个具有事件传递和处理功能的类。
活动:有分配和消费两种方式。
ViewGroup:有分发、拦截、消费三种方法。
显示:有两种方式:分发和消费。
2.2 如何解决View事件冲突?
开发中常见的事件冲突包括ScrollView和RecyclerView滑动冲突,或者RecyclerView内联同方向滑动冲突。
处理滑动冲突的规则:
对于内外滑动方向不匹配导致的滑动冲突,可以根据滑动方向来决定由谁来拦截事件。
对于内外滑动方向一致导致的滑动冲突,您可以根据业务需求指定外层视图何时拦截事件,内层视图何时拦截事件。
以上两种情况交织得比较错综复杂,可以根据自己的需求寻找业务突破口。
如何实现滑动竞争:
外部拦截方式:如果父容器需要该事件,则先拦截点击事件,否则不拦截。具体方法:必须重写父容器的onInterceptTouchEvent方法,内部进行相应的拦截。
内部拦截方式:父容器不拦截事件,将所有事件传递给子容器。如果子容器需要该事件,则直接消费,否则传递给父容器处理。具体方法:必须配合requestDisallowInterceptTouchEvent方法使用。
2.3 显示绘图过程?
DecorView 被加载到Window 中
Activity被创建,从Activity的startActivity开始,最后调用ActivityThread的handleLaunchActivity方法。首先调用performLaunchActivity方法,内部执行Activity的onCreate方法,完成DecorView和Activity的创建。然后调用handleResumeActivity,它首先调用PerformResumeActivity来执行活动的onResume()方法。执行后,获取ActivityClientRecord对象,然后通过r.window.getDecorView()获取DecorView。getWindowManager() 获取WindowManager,最后调用其addView() 方法将DecorView 添加到其中。 WindowManager的实现类是WindowManagerImpl,它内部将addView逻辑委托给WindowManagerGlobal。这里我们可以看到,采用了接口隔离和委托模式,将实现和抽象完全分离。 WindowManagerGlobal的addView()方法不仅将DecorView添加到Window中,还创建了一个ViewRootImpl对象,并通过root.setView()将ViewRootImpl对象和DecorView加载到Window中。这里的ViewRootImpl是ViewRoot的实现类,是WindowManager和DecorView之间的纽带。 View的三大流程都是通过ViewRoot完成的。
2.4 Android中进程和线程的关系有什么区别?
线程是CPU调度的原子单位,线程是有限的系统资源。另一方面,进程通常指的是PC 或移动设备上的程序或应用程序的执行单元。一个app程序通常至少有一个进程,一个进程至少有一个线程(包含与包含) 一般来说,一个app工厂有一个进程,线程就是它的内部生产线。然而,虽然只有一条主线程(即主生产线),但可能存在多个子线程(即副生产线)。进程有自己独立的地址空间,进程内的线程共享该地址空间并且可以同时运行。
2.5 为什么需要IPC?它会导致多进程通信出现问题吗?
在不同进程中运行的所有四个主要组件(活动、服务、接收器和内容提供者)将无法共享数据。这是因为Android为每个应用程序分配了一个独立的虚拟机,而不同的虚拟机的内存分配区域地址不同。结果是同一类对象的多个副本被不同的虚拟机访问。例如常见的例子如开启多个进程以获得更大的内存空间、两个或多个应用程序之间共享数据、微信全家桶等。
一般来说,使用多进程通信时会出现以下问题:
静态成员和单例模式被完全禁用。由于独立虚拟机而发生。由于独立的虚拟机,线程同步机制彻底失效。 SharedPreferences 不太可靠。这可能会导致数据丢失,因为SP 不支持两个进程同时读写。应用程序被创建多次。由于Android系统在创建新进程时会分配一个单独的虚拟机,因此这个进程实际上就是启动应用程序的进程,这当然会创建一个新的应用程序。
2.6 为什么选择Binder?
为什么选择Binder?在我们讨论这个问题之前,知道Android也是基于Linux内核的。 Linux上现有的进程通信方式包括:
管道:在创建时分配页大小的内存,缓冲区大小相对有限。消息队列:信息被复制两次,导致额外的CPU消耗。共享内存:无需复制。缓冲区是共享的。它速度更快,因为它直接连接到进程的虚拟地址空间。然而进程之间的同步问题是操作系统无法实现的,必须使用同步工具来解决各个进程之间的问题。套接字:作为更通用的接口。传输效率较低,主要用于不同机器或跨网络通信。信号量通常用作锁定机制,以防止当进程正在访问共享资源时其他进程访问该资源。因此,它主要用作进程之间以及同一进程内不同线程之间的同步手段。 它不适合信息交换,但适合控制非法内存访问和进程终止等进程中断。
已有IPC方式的情况下,为什么要重新设计Binder机制呢?主要是出于上面列出的三个考虑。
1、效率:影响传输效率的主要因素是内存副本的数量。份数越少,传输速度越高。从Android进程架构角度分析:对于消息队列、socket、管道来说,数据首先从发送方的缓冲区复制到内核开辟的缓冲区,然后再从内核的缓冲区复制到接收方的缓冲区。空间。复制总计,如图所示。
对于Binder来说,数据从发送方的缓冲区复制到内核的缓冲区,完成数据复制的过程是因为接收方的缓冲区和内核的缓冲区映射到了同一个物理地址,如图所示。
共享内存不需要复制,Binder性能仅次于共享内存。
2、稳定性:前面说过,共享内存的性能比Binder要好,所以不使用共享内存的原因是共享内存要处理并发同步问题,不太容易出现死锁和资源占用问题,这是因为它是容易发生冲突,不稳定。 Socket基于C/S架构,但主要用于网络间通信,传输效率较低。 Binder基于C/S架构,服务器端和客户端相对独立,稳定性好。 3、安全性:传统的Linux IPC接收方由于无法获取对方进程可信的UID/PID,因此无法确定对方的身份。 Binder机制为每个进程分配一个UID/PID并使用该UID/PID。在Binder通信期间执行PID有效性测试。
Binder机制的作用和原理?
Linux系统将进程分为用户空间和内核空间。进程不能共享用户空间数据,但可以共享内核空间数据。为了确保安全性和独立性,一个进程不能直接操作或访问另一个进程。这意味着Android进程是独立且相互隔离的。 需要进程之间的数据通信。正常的进程间通信通常需要两个内存副本,如下图所示。
一个完整的Binder IPC通信流程通常是这样的:
首先,Binder驱动在内核空间创建一个缓冲区用于接收数据。接下来,在内核空间中开辟一个内核缓存区,建立内核缓存区与内核中数据接收缓冲区的映射关系,以及内核中数据接收缓冲区与数据接收缓冲区之间的映射关系内核中的区域建立了关系。接收进程的用户空间地址。发送进程通过系统调用copyfromuser()将数据复制到内核中的内核缓存中。这与向用户发送数据相同,因为内核缓存和接收进程的用户空间之间存在内存映射。进程间通信现已完成。
Binder框架中ServiceManager的作用?
Binder框架基于C/S架构。它由一组组件组成,包括客户端、服务器、ServiceManager和binder驱动程序,其中客户端、服务器和服务管理器运行在用户空间,binder驱动程序运行在内核空间。如下所示:
ServerClient:服务器客户端。客户端和服务器之间的通信是在Binder 驱动程序和服务管理器提供的基础架构上执行的。 ServiceManager(类似于DNS域名服务器) Service Manager将Binder名称转换为对客户端中Binder的引用,允许客户端通过Binder名称获取对服务器中Binder实体的引用。 Binder驱动(如路由器):负责建立进程间的Binder通信、计数管理、数据传输和交互等基础支持。
最后来一张Android跨进程通信的高层图:通过Binder机制的详细图解讲解,全面了解:
2.7 AMS 系列中重要术语的解释。
1.ActivityManagerServices(简称AMS)服务器对象。负责系统内所有活动的生命周期。
2.ActivityThread,app的真正入口。打开应用程序后,调用main()开始执行并启动消息循环队列。这就是传说中的UI线程或者主线程。与ActivityManagerService 配合执行完整的活动管理。
3.应用程序线程。用于实现ActivityManagerServie和ActivityThread之间的交互。当ActivityManagerSevice 需要管理关联应用程序内活动的生命周期时,它通过ApplicationThread 的代理对象与ActivityThread 进行通信。
4.ApplicationThreadProxy是服务器端ApplicationThread的代理,负责与客户端ApplicationThread进行通信。 AMS通过这个代理与ActivityThread进行通信。
5.仪器仪表。每个应用程序都只有一个检测对象,并且每个活动都有对该对象的引用。如果您希望ActivityThread 创建或暂停活动,则必须使用检测。执行特定操作。
6.ActivityStack,即AMS中的活动堆栈管理,用于记录激活的活动的顺序关系和状态信息。使用ActivtyStack来确定是否需要启动一个新进程。
7. ActivityRecord,ActivityStack的管理对象每个Activity对应一个AMS ActivityRecord,记录了Activity的状态和其他管理信息。事实上,这是服务器端Activit对象的一个镜像。
8.TaskRecord是AMS抽象出来的“任务”的概念,是一个记录ActivityRecords的栈。 “任务”包含多个ActivityRecord。 AMS 使用TaskRecords 来保证活动开始和结束的顺序。如果你了解Activity的四种launchMode,你应该熟悉这个概念。
2.8 Activity线程工作原理。
2.9 你了解发送和接收广播的原理吗?
继承自BroadcastReceiver并重写onReceive()方法。通过Binder机制向ActivityManagerService注册广播。通过Binder机制向ActivityMangerService发送广播。 ActivityManagerService查找满足广播对应条件(IntentFilter/Permission)的BroadcastReceiver,并将广播发送到BroadcastReceiver所在的消息队列中。 BroadcastReceiver所在的消息队列拾取到该广播后,会回调其onReceive()方法。
2.10APK打包流程
1、使用AAPT工具打包你的资源文件(包括AndroidManifest.xml、布局文件、各种XML资源等)并生成R.java文件。
2、使用AIDL工具处理AIDL文件,生成对应的Java文件。
3、通过Java编译器编译R.java、Java接口文件、Java源文件,生成.class文件。
4、使用dex命令处理.class文件和第三方库的.class文件,生成classes.dex。这个过程主要完成Java字节码到Dalvik字节码的转换、压缩常量池、清除冗余。信息。
5、使用ApkBuilder工具将资源文件和DEX文件打包生成APK文件。
6. 使用Jarsigner工具对KeyStore生成的APK文件进行签名。
7、对于正式版的APK,还使用ZipAlign工具进行对齐过程,将APK文件中的所有资源文件从文件起始距离偏移4字节的整数倍。因此通过内存映射可以更快地访问APK 文件,并减少在设备上运行时的内存占用。
2.11 说说Android虚拟机和Java虚拟机的原理和区别?
JVM、Davilk、ART的原理及区别
JVM和Dalvik虚拟机的区别
JVM:java – javac – .class – jar – .jar
架构: 堆和堆栈架构。
DVM:java – javac – .class – dx.bat – .dex
架构: 个寄存器(CPU 上的缓存)
3.Android优秀三方库源码及架构设计
3.1 基本问题
网络底层
框架:OkHttp实现原理
网络封装框架:Retrofit实现原理
响应式编程框架:RxJava实现原理
图片加载框架:Glide实现原理
事件总线框架:EventBus实现原理
内存泄漏检测框架:LeakCanary实现原理
依赖注入框架:ButterKnife实现原理
依赖全局管理框架:Dagger2实现原理
数据库框架:GreenDao实现原理
MVC MVP MVVM原理和区别?
3.2为什么要在项目中使用OKHTTP这个库?
1.OkHttp 提供了对最新的 HTTP 协议版本 HTTP/2 和 SPDY 的支持,这使得对同一个主机发出的所有请求都可以共享相同的套接字连接。
2.如果 HTTP/2 和 SPDY 不可用,OkHttp 会使用连接池来复用连接以提高效率。
3.OkHttp 提供了对 GZIP 的默认支持来降低传输内容的大小。
4.OkHttp 也提供了对 HTTP 响应的缓存机制,可以避免不必要的网络请求。
5.当网络出现问题时,OkHttp 会自动重试一个主机的多个 IP 地址。
3.3OKhttp针对网络层有哪些优化?
3.4网络请求缓存处理,okhttp如何处理网络缓存的?
3.5从网络加载一个10M的图片,说下注意事项?
3.6WebSocket与socket的区别?
3.7Retrofit优势
1、功能强大:
支持同步、异步
支持多种数据的解析 & 序列化格式
支持RxJava
2、简洁易用:
通过注解配置网络请求参数
采用大量设计模式简化使用
3、可扩展性好:
功能模块高度封装
解耦彻底,如自定义Converters
3.8为什么用Glide
1、多样化媒体加载:不仅可以进行图片缓存,还支持Gif、WebP、缩略图,甚至是Video。
2、通过设置绑定生命周期:可以使加载图片的生命周期动态管理起来。
3、高效的缓存策略:支持内存、Disk缓存,并且Picasso只会缓存原始尺寸的图片,内Glide缓存的是多种规格,也就是Glide会根据你ImageView的大小来缓存相应大小的图片尺寸。
4、内存开销小:默认的Bitmap格式是RGB_565格式,而Picasso默认的是ARGB_8888格式,内存开销小一半。
3.9Glide源码机制的核心思想:
使用一个弱引用map activeResources来盛放项目中正在使用的资源。Lrucache中不含有正在使用的资源。资源内部有个计数器来显示自己是不是还有被引用的情况,把正在使用的资源和没有被使用的资源分开有什么好处呢??因为当Lrucache需要移除一个缓存时,会调用resource.recycle()方法。注意到该方法上面注释写着只有没有任何consumer引用该资源的时候才可以调用这个方法。那么为什么调用resource.recycle()方法需要保证该资源没有任何consumer引用呢?glide中resource定义的recycle()要做的事情是把这个不用的资源(假设是bitmap或drawable)放到bitmapPool中。bitmapPool是一个bitmap回收再利用的库,在做transform的时候会从这个bitmapPool中拿一个bitmap进行再利用。这样就避免了重新创建bitmap,减少了内存的开支。而既然bitmapPool中的bitmap会被重复利用,那么肯定要保证回收该资源的时候(即调用资源的recycle()时),要保证该资源真的没有外界引用了。这也是为什么glide花费那么多逻辑来保证Lrucache中的资源没有外界引用的原因。
3.10Glide内存缓存如何控制大小?
3.11加载bitmap过程(怎样保证不产生内存溢出)
3.12Bitmap如何处理大图,如一张30M的大图,如何预防OOM?
3.13MVP与MVC的主要区别:
1、(最主要区别)View与Model并不直接交互,而是通过与Presenter交互来与Model间接交互。而在MVC中View可以与Model直接交互。
2、Presenter与View的交互是通过接口来进行的,更有利于添加单元测试。
3.14MVC->MVP->MVVM演进过程
MVC -> MVP -> MVVM 这几个软件设计模式是一步步演化发展的,MVVM 是从 MVP 的进一步发展与规范,MVP 隔离了MVC中的 M 与 V 的直接联系后,靠 Presenter 来中转,所以使用 MVP 时 P 是直接调用 View 的接口来实现对视图的操作的,这个 View 接口的东西一般来说是 showData、showLoading等等。M 与 V已经隔离了,方便测试了,但代码还不够优雅简洁,所以 MVVM 就弥补了这些缺陷。在 MVVM 中就出现的 Data Binding 这个概念,意思就是 View 接口的 showData 这些实现方法可以不写了,通过 Binding 来实现。
最后
写到这里也结束了,在文章最后放上一个小小的福利,以下为小编自己在学习过程中整理出的一个学习思路及方向,从事互联网开发,最主要的是要学好技术,而学习技术是一条慢长而艰苦的道路,不能靠一时激情,也不是熬几天几夜就能学好的,必须养成平时努力学习的习惯,更加需要准确的学习方向达到有效的学习效果。
以 MVVM 就弥补了这些缺陷。在 MVVM 中就出现的 Data Binding 这个概念,意思就是 View 接口的 showData 这些实现方法可以不写了,通过 Binding 来实现。
最后
写到这里也结束了,在文章最后放上一个小小的福利,以下为小编自己在学习过程中整理出的一个学习思路及方向,从事互联网开发,最主要的是要学好技术,而学习技术是一条慢长而艰苦的道路,不能靠一时激情,也不是熬几天几夜就能学好的,必须养成平时努力学习的习惯,更加需要准确的学习方向达到有效的学习效果。
[外链图片转存中…(img-wCW47Vfa-1719249680845)]
#以上关于2024上半年百度Android岗(初级到高级)面试真题全收录+解析,备战金九银十!的相关内容来源网络仅供参考,相关信息请以官方公告为准!
原创文章,作者:CSDN,如若转载,请注明出处:https://www.sudun.com/ask/92129.html