腾讯 Android 中高级面试题大全(含解析)
(1) volatile 是变量修饰符,而 synchronized 则作用于一段代码或者方法。(2) volatile 只是在线程内存和 main memory(主内存)间同步某个变量的值;而 synchronized 通过锁定和解锁某个监视器同步所有变量的值。显然 synchronized 要比 volatile 消耗更多资源。const、final、lock
12. 界面卡顿的原因有哪些?
UI 线程(main)有耗时操作视图渲染时间过长,导致卡顿
13. 造成 OOM/ANR 的原因?
OOM: (1)不恰当地使用 static 关键字 (2)内部类对 Activity 的引用 (3)大量 Bitmap 的使用会导致程序包运行时的内存消耗变大 (4)游标 Cursor 对象用完应该及时关闭 (5)加载对象过大 (6)相应资源过多,来不及释放。ANR: (1)在 5 秒内没有响应输入的事件(IO 操
作耗时、数据库操作复杂耗时、主线程非主线程产生死锁等待、网络加载/图片操作耗时、硬件操作耗时) (2)BroadcastReceiver 在 10 秒内没有执行完毕(Service binder 数量达到上限、Service 忙导致超时无响应)
14. Activity 与 Fragment 生命周期有何联系
在创建的过程中,是 Activity 带领着 Fragment,在销毁的过程中,是 Fragment 带领着 Activity。
15. Glide 三级缓存
内存缓存,磁盘缓存、网络缓存(由于网络缓存严格来说不算是缓存的一种,故也称为二级缓存)。缓存的资源分为两种:原图(SOURCE)、处理图(RESULT)(默认)。内存缓存:默认开启的,可以通过调用 skipMemoryCache(true)来设置跳过内存缓存,缓存最大空间:每个进程可用的最大内存*0.4。(低配手机 0.33)磁盘缓存:分为四种:ALL(缓存原图)、NONE(什么都不缓存)、SOURCE(只缓存原图)、RESULT(之后处理图),通过 diskCacheStrategy(DiskCacheStrategy.ALL)来设置,缓存大小 250M。
16. 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。
17. 数据库的操作类型有哪些,如何导入外部数据库?
(1) 增删改查(2) 将外部数据库放在项目的 res/raw 目录下。因为安卓系统下数据库要放在 data/data/packagename/databases 的目录下,然后要做的就是将外部数据库导入到该目录下,操作方法是通过 FileInputStream 读取外部数据库,再用 FileOutputStrean 把读取到的东西写入到该目录下。
18. 是否使用过 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) 进程间通信
19. 是否使用过本地广播,和全局广播有什么差别?
本地广播的数据在本应用范围内传播,不用担心隐私数据泄露的问题。不用担心别的应用伪造广播,造成安全隐患。相比在系统内发送全局广播,它更高效。
20. Activity、 Window、 View 三者的差别, fragment 的特点?
(1) Activity 像一个工匠(控制单元),Window 像窗户(承载模型),View 像窗花(显示视图) LayoutInflater 像剪刀,Xml 配置像窗花图纸。(2) a. Fragment 可以作为 Activity 界面的一部分组成出现;b. 可以在一个 Activity 中同时出现多个 Fragment,并且一个 Fragment 也可以在多个 Activity 中使用;c. 在 Activity 运行过程中,可以添加、移除或者替换 Fragment;d. Fragment 可以响应自己的输入事件,并且有自己的生命周期,它们的生命周期会受宿主 Activity 的生命周期影响。
21. Handler、 Thread 和 HandlerThread 的差别
从 Android 中 Thread(java.lang.Thread -> java.lang.Object)描述可以看出,Android 的 Thread 没有对 Java 的 Thread 做任何封装,但是 Android 提供了一个继承自 Thread 的类 HandlerThread(android.os.HandlerThread -> java.lang.Thread),这个类对 Java 的 Thread 做了很多便利 Android 系统的封装。android.os.Handler 可以通过 Looper 对象实例化,并运行于另外的线程中,Android 提供了让 Handler 运行于其它线程的线程实现,也是就 HandlerThread。HandlerThread 对象 start 后可以获得其 Looper 对象,并且使用这个 Looper 对象实例 Handler。
22. 低版本 SDK 实现高版本 api
自己实现或使用注解 @TargetApi annotation
23. launch mode 应用场景
(1) standard:标准的启动模式。
(2) singleTop:单一顶部模式
如果 Activity 已经被开启,并且处于任务栈的栈顶,就不会创建新的 Activity,而是复用这个已经开启的 Activity。为了防止出现一些奇怪的用户体验,推荐使用单一顶部模式,整个任务栈可以有多个实例存在.应用场景:短信发送界面.
(3)singletask:单一任务栈
在整个任务栈里面只允许有一个当前 Activity 的实例存在如果要开启的 Activity 在任务栈中已经存在,直接复用这个已经存在的 Activity,并且把这个 Activity 上面的所有的其他 Activity 给清空应用场景:如果一个 Activity 非常消耗内存和 cpu 资源,建议把这个 Activity 做成 singletask 的模式。浏览器的 browserActivity
(4)singleinstance:单一实例.
整个手机操作系统只有一个实例存在,并且是运行在自己单独的任务栈里面.应用场景:通话界面的 Activity
24. touch 事件传递流程
事件处理包括三种情况,分别为:传递—-dispatchTouchEvent()函数、拦截——onInterceptTouchEvent()函数、消费—-onTouchEvent()函数和 OnTouchListener。Android 事件传递流程:(1) 事件都是从 Activity.dispatchTouchEvent()开始传递(2) 事件由父 View 传递给子 View,ViewGroup 可以通过 onInterceptTouchEvent()方法对事件拦截,停止其向子 view 传递(3) 如果事件从上往下传递过程中一直没有被停止,且最底层子 View 没有消费事件,事件会反向往上传递,这时父 View(ViewGroup)可以进行消费,如果还是没有被消费的话,最后会到 Activity 的 onTouchEvent()函数。(4) 如果 View 没有对 ACTION_DOWN 进行消费,之后的其他事件不会传递过来,也就是说 ACTION_DOWN 必须返回 true,之后的事件才会传递进来(5) OnTouchListener 优先于 onTouchEvent()对事件进行消费
View 不处理事件流程图
View 处理事件流程图
事件拦截
25.Android 性能优化
一、代码优化 1.使用 AndroidLint 分析结果进行相应优化 2.不使用枚举及 IOC 框架,反射性能低 3.常量加 static4.静态方法 5.减少不必要的对象、成员变量 6.尽量使用线程池 7.适当使用软引用和弱引用 8.尽量使用静态内部类,避免潜在的内存泄露 9.图片缓存,采用内存缓存 LRUCache 和硬盘缓存 DiskLRUCache10.Bitmap 优化,采用适当分辨率大小并及时回收二、布局优化避免 OverDraw 过渡绘制优化布局层级避免嵌套过多无用布局当我们在画布局的时候,如果能实现相同的功能,优先考虑相对布局,然后在考虑别的布局,不要用绝对布局。使用标签把复杂的界面需要抽取出来使用标签,因为它在优化 UI 结构时起到很重要的作用。目的是通过删减多余或者额外的层级,从而优化整个 Android Layout 的结构。核心功能就是减少冗余的层次从而达到优化 UI 的目的!ViewStub 是一个隐藏的,不占用内存空间的视图对象,它可以在运行时延迟加载布局资源文件。三、ListView 和 GridView 优化 1.采用 ViewHolder 复用 convertView2.避免在 getView 中执行耗时操作 3.列表在滑动状态时不加载图片 4.开启硬件加速
26.Android 内存泄漏
内存泄漏简单地说就是申请了一块内存空间,使用完毕后没有释放掉。它的一般表现方式是程序运行时间越长,占用内存越多,最终用尽全部内存,整个系统崩溃。由程序申请的一块内存,且没有任何一个指针指向它,那么这块内存就泄露了。可能的原因有:1.注册没取消造成内存泄露,如:广播 2.静态变量持有 Activity 的引用 3.单例模式持有 Activity 的引用 4.查询数据库后没有关闭游标 cursor5.构造 Adapter 时,没有使用 convertView 重用 6.Bitmap 对象不在使用时调用 recycle()释放内存 7.对象被生命周期长的对象引用,如 activity 被静态集合引用导致 activity 不能释放
评论