美文网首页
【金九银十面试冲刺】Android岗面试题每日分享——Andro

【金九银十面试冲刺】Android岗面试题每日分享——Andro

作者: 小城哇哇 | 来源:发表于2023-08-08 15:39 被阅读0次

一、Activity 与 Fragment 之间常见的几种通信方式?

viewModel 做数据管理,activity 和 fragment 公用同个viewModel 实现数据传递

二、LaunchMode 的应用场景?

LaunchMode 有四种,分别为 Standard, SingleTop,SingleTask 和 SingleInstance,每种模式的实现原理一楼都做了较详细说明,下面说一下具体使用场景:

  • Standard:
    Standard模式是系统默认的启动模式,一般我们 app 中大部分页面都是由该模式的页面构成的,比较常见的场景是:社交应用中,点击查看用户A信息->查看用户A 粉丝->在粉丝中挑选查看用户B信息->查看用户A粉丝... 这种情况下一般我们需要保留用户操作 Activity栈的页面所有执行顺序。
  • SingleTop:
    SingleTop 模式一般常见于社交应用中的通知栏行为功能,例如:App 用户收到几条好友请求的推送消息,需要用户点击推送通知进入到请求者个人信息页,将信息页设置为 SingleTop 模式就可以增强复用性。
  • SingleTask
    SingleTask 模式一般用作应用的首页,例如浏览器主页,用户可能从多个应用启动浏览器,但主界面仅仅启动一次,其余情况都会走onNewIntent,并且会清空主界面上面的其他页面。
  • SingleInstance:
    SingleInstance 模式常应用于独立栈操作的应用,如闹钟的提醒页面,当你在A应用中看视频时,闹钟响了,你点击闹钟提醒通知后进入提醒详情页面,然后点击返回就再次回到A的视频页面,这样就不会过多干扰到用户先前的操作了。

三、BroadcastReceiver 与LocalBroadcastReceiver 有什么区别?

  • BroadcastReceiver 是跨应用广播,利用Binder机制实现,支持动态和静态两种方式注册方式。
  • LocalBroadcastReceiver 是应用内广播,利用Handler 实现,利用了IntentFilter的match功能,提供消息的发布与接收功能,实现应用内通信,效率和安全性比较高,仅支持动态注册。

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

  1. 生命周期上的区别
    执行startService时,Service会经历onCreate- >onStartCommand。当执行stopService时,直接调用onDestroy方法。调用者如果没有stopService,Service 会一直在后台运行,下次调用者再起来仍然可以stopService。执行bindService时,Service会经历onCreate- >onBind。这个时候调用者和Service绑定在一起。调用者调用unbindService方法或者调用者Context不存在了(如Activity被finish了),Service就会调用onUnbind- >onDestroy。这里所谓的绑定在一起就是说两者共存亡了。多次调用startService,该Service只能被创建一次,即该Service的onCreate方法只会被调用一次。但是每次调用startService,onStartCommand方法都会被调用。Service的onStart方法在API 5时被废弃,替代它的是onStartCommand方法。第一次执行bindService时,onCreate和onBind方法会被调用,但是多次执行bindService时,onCreate和onBind 方法并不会被多次调用,即并不会多次创建服务和绑定服务。
  2. 调用者如何获取绑定后的Service的方法
    onBind回调方法将返回给客户端一个IBinder接口实例,IBinder允许客户端回调服务的方法,比如得到Service运行的状态或其他操作。我们需要IBinder对象返回具体的Service对象才能操作,所以说具体的Service对象必须首先实现Binder对象。
  3. 既使用startService又使用bindService的情况
    如果一个Service又被启动又被绑定,则该Service会一直在后台运行。首先不管如何调用,onCreate始终只会调用一次。对应startService调用多少次,Service的onStart 方法便会调用多少次。Service的终止,需要unbindService和stopService同时调用才行。不管startService与bindService的调用顺序,如果先调用unbindService,此时服务不会自动终止,再调用stopService之后,服务才会终止;如果先调用stopService,此时服务也不会终止,而再调用unbindService或者之前调用bindService的Context不存在了(如Activity被finish的时候)之后,服务才会自动停止。
    那么,什么情况下既使用startService,又使用bindService呢?
    如果你只是想要启动一个后台服务长期进行某项任务,那么使用startService便可以了。如果你还想要与正在运行的Service取得联系,那么有两种方法:一种是使用broadcast,另一种是使用bindService。前者的缺点是如果交流较为频繁,容易造成性能上的问题,而后者则没有这些问题。因此,这种情况就需要startService和bindService一起使用了。
    另外,如果你的服务只是公开一个远程接口,供连接上的客户端(Android的Service是C/S架构)远程调用执行方法,这个时候你可以不让服务一开始就运行,而只是bindService,这样在第一次bindService的时候才会创建服务的实例运行它,这会节约很多系统资源,特别是如果你的服务是远程服务,那么效果会越明显(当然在Servcie创建的是偶会花去一定时间,这点需要注意)。
  4. 本地服务与远程服务
    本地服务依附在主进程上,在一定程度上节约了资源。本地服务因为是在同一进程,因此不需要IPC,也不需要AIDL。相应
    bindService会方便很多。缺点是主进程被kill后,服务变会终止。远程服务是独立的进程,对应进程名格式为所在包名加上你指定的android:process字符串。由于是独立的进程,因此在Activity所在进程被kill的是偶,该服务依然在运行。缺点是该服务是独立的进程,会占用一定资源,并且使用AIDL进行IPC稍微麻烦一点。对于startService来说,不管是本地服务还是远程服务,我们需要做的工作都一样简单。

五、谈谈你对 Activity.runOnUiThread 的理解?

一般是用来将一个runnable绑定到主线程,在runOnUiThread源码里面会判断当前runnable是否是主线程,如果是直接run,如果不是,通过一个默认的空构造函数handler将runnable post 到looper里面,创建构造函数handler,会默认绑定一个主线程的looper对象

六、子线程能否更新UI?为什么?

子线程是不能直接更新UI的
注意这句话,是不能直接更新,不是不能更新(极端情况下可更新)绘制过程要保持同步(否则页面不流畅),而我们的主线程负责绘制ui,极端情况就是,在Activity的onResume(含)之前的生命周期中子线程都可以进行更新ui,也就是onCreate,onStart和onResume,此时主线程的绘制还没开始。

七、 谈谈 Handler 机制和原理?

首先在UI线程我们创建了一个Handler实例对象,无论是匿名内部类还是自定义类生成的Handler实例对象,我们都需要对handleMessage方法进行重写,在handleMessage方法中我们可以通过参数msg来写接受消息过后UIi线程的逻辑处理,接着我们创建子线程,在子线程中需要更新UI的时候,新建一个Message对象,并且将消息的数据记录在这个消息对象Message的内部,比如arg1,arg2,obj等,然后通过前面的Handler实例对象调用sendMessge方法把这个Message实例对象发送出去,之后这个消息会被存放于MessageQueue中等待被处理,此时MessageQueue的管家Looper正在不停的把MessageQueue存在的消息取出来,通过回调dispatchMessage方法将消息传递给Handler的handleMessage方法,最终前面提到的消息会被Looper 从MessageQueue中取出来传递给handleMessage方法。

八、简述一下 Android 中 UI 的刷新机制?

1、界面刷新的本质流程

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

2、同步屏障的作用

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

3、同步屏障的原理?

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

九、谈谈Android的事件分发机制?

当点击的时候,会先调用顶级viewgroup的dispatchTouchEvent,如果顶级的viewgroup拦截了此事件(onInterceptTouchEvent返回true),则此事件序列 由顶级viewgroup处理。如果顶级viewgroup设置setOnTouchListener,则会回调接口中的onTouch,此时顶级的viewgroup中的onTouchEvent不再回调,如果不设 置setOnTouchListener则onTouchEvent会回调。如果顶级viewgroup设置setOnClickListener,则会回调接口中的onClick。如果顶级viewgroup不拦截事件,事件就会向下传递给他的子view,然后子view就会调用它的dispatchTouchEvent方法。

十、谈谈如何优化ListView?

ViewHolder什么的持有View预加载/懒加载数据什么的
大招:用RecyclerView替换ListView
绝招:直接删除控件

十一、谈谈自定义LayoutManager的流程?

  1. 确定Itemview的LayoutParams generateDefaultLayoutParams
  2. 确定所有itemview在recyclerview的位置,并且回收和复用itemview onLayoutChildren
  3. 添加滑动canScrollVertically

十二、谈一谈获取View宽高的几种方法?

  1. OnGlobalLayoutListener获取
  2. OnPreDrawListener获取
  3. OnLayoutChangeListener获取
  4. 重写View的onSizeChanged()
  5. 使用View.post()方法

十三、Kotlin 中infix 关键字的原理和使用场景?

使用场景是用来修饰函数,使用了 infix 关键字的函数称为中缀函数,使用时可以省略 点表达式和括号。让代码看起来更加优雅,更加语义化。原理不过是编译器在语法层面给与了支持,编译为 Java代码后可以看到就是普通的函数调用。kotlin 的很多特性都是在语法和编译器上的优化。

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

kotlin存在四种可见性修饰符,默认是public。 private、protected、internal、public

  1. private、protected、public是和java中的一样的。
  2. 不同的是java中默认是default修饰符(包可见),而kotlin存在internal修饰符(模块内部可见)。
  3. kotlin可以直接在文件顶级声明方法、变量等。其中protected不能用来修饰在文件顶级声明的类、方法、变量等。构造方法默认是public修饰,可以使用可见性修饰符修饰constructor关键字来改变构造方法的可见性。

十五、请谈谈你对Binder机制的理解?

Binder机制:

  1. 为了保证进程空间不被其他进程破坏或干扰,Linux中的进程是相互独立或相互隔离的。
  2. 进程空间分为用户空间和内核空间。用户空间不可以进行数据交互;内核空间可以进行数据交互,所有进程共用一个内核空间。
  3. Binder机制相对于Linux内传统的进程间通信方式:
    (1)性能更好;Binder机制只需要拷贝数据一次,管道、 消息队列、Socket等都需要拷贝数据两次;而共享内存虽然不需要拷贝,但实现复杂度高。
    (2)安全性更高;Binder机制通过UID/PID在内核空间添加了身份标识,安全性更高。
  4. Binder跨进程通信机制:基于C/S架构,由Client、Server、ServerManager和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接口),即具备了跨进程通信的能力

最后

我整理了一套Android面试题合集,也包括以上面试题,有需要完整面试题和答案解析的朋友可以关注哇哇,以上均可分享哦~!!!

image

相关文章

网友评论

      本文标题:【金九银十面试冲刺】Android岗面试题每日分享——Andro

      本文链接:https://www.haomeiwen.com/subject/oegnpdtx.html