写点什么

1549 页 Android 最新面试题含答案,成功入职腾讯

用户头像
Android架构
关注
发布于: 58 分钟前

[](

)22.Java 中实现多态的机制是什么?


答:方法的重写 Overriding 和重载 Overloading 是 Java 多态性的不同表现


重写 Overriding 是父类与子类之间多态性的一种表现


重载 Overloading 是一个类中多态性的一种表现.

[](

)23.说说你对 Java 反射的理解


JAVA 反射机制是在运行状态中, 对于任意一个类, 都能够知道这个类的所有属性和方法; 对于任意一个对象, 都能够调用它的任意一个方法和属性。 从对象出发,通过反射(Class 类)可以取得取得类的完整信息(类名 Class 类型,所在包、具有的所有方法 Method[]类型、某个方法的完整信息(包括修饰符、返回值类型、异常、参数类型)、所有属性 Field[]、某个属性的完整信息、构造器 Constructors),调用类的属性或方法自己的总结: 在运行过程中获得类、对象、方法的所有信息。

[](

)24.说说你对 Java 注解的理解


元注解


元注解的作用就是负责注解其他注解。java5.0 的时候,定义了 4 个标准的 meta-annotation 类型,它们用来提供对其他注解的类型作说明。


1.@Target


2.@Retention


3.@Documented


4.@Inherited


**由于篇幅有限,只能分享部分面试题,更多面试题及答案可以我的[【Github】](


)阅读下载哦~无偿分享给大家,算是一个感恩回馈吧**




[](


)二、Android 面试题(基础+进阶)(必须)


========================================================================================

[](

)1.四大组件是什么(这个不知道的话,没必要去面试了,转行吧)


Android 四大组件有 Activity,Service 服务,Content Provider 内容提供,BroadcastReceiver。

[](

)2.四大组件的生命周期和简单用法


activity:onCreate() -> onStart() -> onResume() -> onPause


《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》
浏览器打开:qq.cn.hn/FTe 免费领取
复制代码


() -> onStop() -> onDetroy()


Service:


service 启动方式有两种,一种是通过 startService()方式进行启动,另一种是通过 bindService()方式进行启动。不同的启动方式他们的生命周期是不一样.


通过 startService()这种方式启动的 service,生命周期是这样:调用 startService() --> onCreate()–> onStartConmon()–> onDestroy()。这种方式启动的话,需要注意一下几个问题,第一:当我们通过 startService 被调用以后,多次在调用 startService(),onCreate()方法也只会被调用一次,而 onStartConmon()会被多次调用当我们调用 stopService()的时候,onDestroy()就会被调用,从而销毁服务。第二:当我们通过 startService 启动时候,通过 intent 传值,在 onStartConmon()方法中获取值的时候,一定要先判断 intent 是否为 null。


通过 bindService()方式进行绑定,这种方式绑定 service,生命周期走法:bindService–>onCreate()–>onBind()–>unBind()–>onDestroy() bingservice 这种方式进行启动 service 好处是更加便利 activity 中操作 service,比如加入 service 中有几个方法,a,b ,如果要在 activity 中调用,在需要在 activity 获取 ServiceConnection 对象,通过 ServiceConnection 来获取 service 中内部类的类对象,然后通过这个类对象就可以调用类中的方法,当然这个类需要继承 Binder 对象


contentProvider:contentProvider 的生命周期、理解应该跟进程一样,它作为系统应用组件、其生命周期应该跟 app 应用的生命周期类似,只是它属于系统应用、所以随系统启动而初始化,随系统关机而结束;但也存在其他状态下结束进程、比如说系统内存不够时,进行内存回收、会根据生成时间态、用户操作等情况进行是否内存回收。


BroadcastReceiver:广播的生命周期从调用开始到 onReceiver 执行完毕结束,需要注意的是,一般广播的生命周期都极短,需要在 10s 内处理完 onReceiver 中的所有工作,所以,一般不进行耗时长的工作,如果有耗时长的工作,应当通过 Intent 传递给 Service 进行处理。(注意,不要在 onReceiver 中开启线程进行耗时任务处理,否则,在 10s 后,该线程会变成空线程,从而导致任务的丢失。同样的,也不要使用 bindService 来绑定服务。)


值得注意的是,如果是在代码中动态注册的广播,如:在 Activity 注册,那么在 Activity 的 onDestory 中需要使用 unregisterReceiver 注销广播。

[](

)3.Activity 之间的通信方式


Intent


借助类的静态变量


借助全局变量/Application


借助外部工具


借助 SharedPreference


使用 Android 数据库 SQLite


赤裸裸的使用 File


Android 剪切板


借助 Service

[](

)4.横竖屏切换的时候,Activity 各种情况下的生命周期


分两种情况:


1.不设置 Activity 的 android:configChanges,或设置 Activity 的 android:configChanges=“orientation”,或设置 Activity 的 android:configChanges=“orientation|keyboardHidden”,切屏会重新调用各个生命周期,切横屏时会执行一次,切竖屏时会执行一次。


横竖屏切换造成 activity 的生命周期


onPause()-onSaveInstanceState()-onStop()-onDestroy()-onCreat()-onStart()-onRestoreInstanceState()-onResume()即会导致 activity 的销毁和重建 。


2.配置 android:configChanges=“orientation|keyboardHidden|screenSize”,才不会销毁 activity,且只调用 onConfigurationChanged 方法。


onSaveInstanceState() 与 onRestoreIntanceState() 资源相关的系统配置发生改变或者资源不足时(例如屏幕旋转),当前 Activity 会销毁,并且在 onStop 之前回调 onSaveInstanceState 保存数据,在重新创建 Activity 的时候在 onStart 之后回调 onRestoreInstanceState。其中 Bundle 数据会传到 onCreate(不一定有数据)和 onRestoreInstanceState(一定有数据)。


用户或者程序员主动去销毁一个 Activity 的时候不会回调(如代码中 finish()或用户按下 back,不会回调),其他情况都会调用,来保存界面信息。

[](

)5.Activity 与 Fragment 之间生命周期比较


a. 在创建的过程中,是 Activity 带领 Fragment 执行生命周期的方法,所以它们生命周期执行的顺序如下:


Activity – onCreate() ,


Fragment – onAttach() -> onCreate() -> onCreateView() -> onActivityCreated


Activity – onStart()


Fragment – onStart()


Activity – onResume()


Fragment – onResume()


最后,在销毁时是 Fragment 带领 Activity 执行生命周期的方法:


Fragment – onPause()


Activity – onPause()


Fragment – onStop()


Activity – onStop()


Fragment – onDestroyView() -> onDestroy() -> onDetach()


Activity – onDestroy()

[](

)6.Activity 上有 Dialog 的时候按 Home 键时的生命周期


有 Dialog 和 无 Dialog 按 Home 键效果一样:


正常启动: onCreate() -> onStart() -> onResume()


按 home 键: onPause() -> onStop()


再次启动: onRestart() -> onStart() -> onResume()

[](

)7.两个 Activity 之间跳转时必然会执行的是哪几个方法?


a. 正常情况下 Activity A 跳转到 Activity B 时:


A 调用 onCreate() 方法 -> onStart() 方法 -> onResume() 方法,此时 A 前台可见。当 A 跳转到 B 时,A 调用 onPause() 方法,然后调用新的 Activity B 中的 onCreate() 方法 -> onStart() 方法 -> onResume() 方法。最后 A 再调用 onStop()方法。


b. 当 Activity B 为透明主题时:


除了最后 Activity A 不调用 onStop() 方法之外,其它都和 a 中的一样。

[](

)8.Activity 的四种启动模式对比


此处延伸:栈(First In Last Out)与队列(First In First Out)的区别


区别:队列先进先出,栈先进后出


对插入和删除操作的"限定"。 栈是限定只能在表的一端进行插入和删除操作的线性表。 队列是限定只能在表的一端进行插入和在另一端进行删除操作的线性表。


遍历数据速度不同


standard 模式


这是默认模式,每次激活 Activity 时都会创建 Activity 实例,并放入任务栈中。使用场景:大多数 Activity。


singleTop 模式


如果在任务的栈顶正好存在该 Activity 的实例,就重用该实例( 会调用实例的 onNewIntent() ),否则就会创建新的实例并放入栈顶,即使栈中已经存在该 Activity 的实例,只要不在栈顶,都会创建新的实例。使用场景如新闻类或者阅读类 App 的内容页面。


singleTask 模式


如果在栈中已经有该 Activity 的实例,就重用该实例(会调用实例的 onNewIntent() )。重用时,会让该实例回到栈顶,因此在它上面的实例将会被移出栈。如果栈中不存在该实例,将会创建新的实例放入栈中。使用场景如浏览器的主界面。不管从多少个应用启动浏览器,只会启动主界面一次,其余情况都会走 onNewIntent,并且会清空主界面上面的其他页面。


singleInstance 模式


在一个新栈中创建该 Activity 的实例,并让多个应用共享该栈中的该 Activity 实例。一旦该模式的 Activity 实例已经存在于某个栈中,任何应用再激活该 Activity 时都会重用该栈中的实例( 会调用实例的 onNewIntent() )。其效果相当于多个应用共享一个应用,不管谁激活该 Activity 都会进入同一个应用中。使用场景如闹铃提醒,将闹铃提醒与闹铃设置分离。singleInstance 不要用于中间页面,如果用于中间页面,跳转会有问题,比如:A -> B (singleInstance) -> C,完全退出后,在此启动,首先打开的是 B。

[](

)9.Activity 状态保存于恢复


当 Activity 在异常情况( 系统内存不足或者系统配置发生了改变等 )被销毁重建后, 在销毁的时候 Activity 会调用 onSaveInstanceState() 方法用于保存 Activity 相关的状态和数据,然后在重建后的 Activity 的中我们可以通过 onCreate() 或者 onRestoreInstanceState() 方法恢复数据,这里我们需要注意的是如果通过 onCreate() 方法恢复,那么得先判断它的 intent 参数 是否为空,如果在 onRestoreInstanceState() 方法恢复就不会,因为只要 onRestoreInstanceState() 方法被调用就说明一定有数据,不会为空。Google 推荐使用 onRestoreInstanceState() 方法。

[](

)10.如何实现 Fragment 的滑动?


将 Fragment 与 viewpager 绑定,通过 viewpager 中的 touch 事件,会进行 move 事件的滑动处理。

[](

)11.fragment 之间传递数据的方式?


1、在 fragment 中设置一个方法,然后进行调用


2、采取接口回调的方式进行数据传递。


3、广播或者是使用三方开源框架:EventBus

[](

)12.Activity 怎么和 Service 绑定?怎么在 Activity 中启动自己对应的 Service?


1、activity 能进行绑定得益于 Serviece 的接口。为了支持 Service 的绑定,实现 onBind 方法。


2、Service 和 Activity 的连接可以用 ServiceConnection 来实现。需要实现一个新的 ServiceConnection,重现 onServiceConnected 和 OnServiceDisconnected 方法,一旦连接建立,就能得到 Service 实例的引用。


3、执行绑定,调用 bindService 方法,传入一个选择了要绑定的 Service 的 Intent(显示或隐式)和一个你实现了的 ServiceConnection 的实例

[](

)13.service 和 activity 怎么进行数据交互?


1.通过 broadcast:通过广播发送消息到 activitry


2.通过 Binder:通过与 activity 进行绑定


(1)添加一个继承 Binder 的内部类,并添加相应的逻辑方法。


(2)重写 Service 的 onBind 方法,返回我们刚刚定义的那个内部类实例。


(3)Activity 中创建一个 ServiceConnection 的匿名内部类,并且 重 写 里 面 的 onServiceConnected 方 法 和 onServiceDisconnected 方法,这两个方法分别会在活动与服务成功绑定以及解除绑定的时候调用(在 onServiceConnected 方法中,我们可以得到一个刚才那个 service 的 binder 对象,通过对这个 binder 对象进行向下转型,得到我们那个自定义的 Binder 实例,有了这个实例,做可以调用这个实例里面的具体方法进行需要的操作了)。

[](

)14.Service 的开启方式,请描述一下 Service 的生命周期,请描述一下 Service 的生命周期


service 启动方式有两种,一种是通过 startService()方式进行启动,另一种是通过 bindService()方式进行启动。不同的启动方式他们的生命周期是不一样.


通过 startService()这种方式启动的 service,生命周期是这样:调用 startService() --> onCreate()–> onStartConmon()–> onDestroy()。这种方式启动的话,需要注意一下几个问题,第一:当我们通过 startService 被调用以后,多次在调用 startService(),onCreate()方法也只会被调用一次,而 onStartConmon()会被多次调用当我们调用 stopService()的时候,onDestroy()就会被调用,从而销毁服务。第二:当我们通过 startService 启动时候,通过 intent 传值,在 onStartConmon()方法中获取值的时候,一定要先判断 intent 是否为 null。


通过 bindService()方式进行绑定,这种方式绑定 service,生命周期走法:bindService–>onCreate()–>onBind()–>unBind()–>onDestroy() bingservice 这种方式进行启动 service 好处是更加便利 activity 中操作 service,比如加入 service 中有几个方法,a,b ,如果要在 activity 中调用,在需要在 activity 获取 ServiceConnection 对象,通过 ServiceConnection 来获取 service 中内部类的类对象,然后通过这个类对象就可以调用类中的方法,当然这个类需要继承 Binder 对象

[](

)15.请描述一下广播 BroadcastReceiver 的理解


广播,是一个全局的监听器,属于 Android 四大组件之一。Android 广播分为两个角色:广播发送者、广播接收者。作用是监听 / 接收 应用 App 发出的广播消息,并 做出响应


可应用在:


Android 不同组件间的通信(含 :应用内 / 不同应用之间)


多线程通信


与 Android 系统在特定情况下的通信


如:电话呼入时、网络可用时

[](

)16.Broadcast 注册方式与区别 (此处延伸:什么情况下用动态注册)


Broadcast 广播,注册方式主要有两种.


第一种是静态注册,也可成为常驻型广播,这种广播需要在 Androidmanifest.xml 中进行注册,这中方式注册的广播,不受页面生命周期的影响,即使退出了页面,也可以收到广播这种广播一般用于想开机自启动啊等等,由于这种注册的方式的广播是常驻型广播,所以会占用 CPU 的资源。


第二种是动态注册,而动态注册的话,是在代码中注册的,这种注册方式也叫非常驻型广播,收到生命周期的影响,退出页面后,就不会收到广播,我们通常运用在更新 UI 方面。这种注册方式优先级较高。最后需要解绑,否会会内存泄露


广播是分为有序广播和无序广播。

[](

)17.本地广播和全局广播有什么差别?


BroadcastReceiver 是针对应用间、应用与系统间、应用内部进行通信的一种方式


LocalBroadcastReceiver 仅在自己的应用内发送接收广播,也就是只有自己的应用能收到,数据更加安全广播只在这个程序里,而且效率更高。

[](

)18.BroadcastReceiver,LocalBroadcastReceiver 区别


一、应用场景不同


1、BroadcastReceiver 用于应用之间的传递消息;


2、而 LocalBroadcastManager 用于应用内部传递消息,比 broadcastReceiver 更加高效。


二、使用安全性不同


1、BroadcastReceiver 使用的 Content API,所以本质上它是跨应用的,所以在使用它时必须要考虑到不要被别的应用滥用;


2、LocalBroadcastManager 不需要考虑安全问题,因为它只在应用内部有效。

[](

)19.AlertDialog,popupWindow 区别


(1)Popupwindow 在显示之前一定要设置宽高,Dialog 无此限制。


(2)Popupwindow 默认不会响应物理键盘的 back,除非显示设置了 popup.setFocusable(true);而在点击 back 的时候,Dialog 会消失。


(3)Popupwindow 不会给页面其他的部分添加蒙层,而 Dialog 会。


(4)Popupwindow 没有标题,Dialog 默认有标题,可以通过 dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);取消标题


(5)二者显示的时候都要设置 Gravity。如果不设置,Dialog 默认是 Gravity.CENTER。


(6)二者都有默认的背景,都可以通过 setBackgroundDrawable(new ColorDrawable(android.R.color.transparent));去掉。


最本质的区别:AlertDialog 是非阻塞式对话框:AlertDialog 弹出时,后台还可以做事情;而 PopupWindow 是阻塞式对话框:PopupWindow 弹出时,程序会等待,在 PopupWindow 退出前,程序一直等待,只有当我们调用了 dismiss 方法的后,PopupWindow 退出,程序才会向下执行。

[](

)20.讲解一下 Context


Context 是一个抽象基类。在翻译为上下文,也可以理解为环境,是提供一些程序的运行环境基础信息。Context 下有两个子类,ContextWrapper 是上下文功能的封装类,而 ContextImpl 则是上下文功能的实现类。而 ContextWrapper 又有三个直接的子类, ContextThemeWrapper、Service 和 Application。其中,ContextThemeWrapper 是一个带主题的封装类,而它有一个直接子类就是 Activity,所以 Activity 和 Service 以及 Application 的 Context 是不一样的,只有 Activity 需要主题,Service 不需要主题。Context 一共有三种类型,分别是 Application、Activity 和 Service。这三个类虽然分别各种承担着不同的作用,但它们都属于 Context 的一种,而它们具体 Context 的功能则是由 ContextImpl 类去实现的,因此在绝大多数场景下,Activity、Service 和 Application 这三种类型的 Context 都是可以通用的。不过有几种场景比较特殊,比如启动 Activity,还有弹出 Dialog。出于安全原因的考虑,Android 是不允许 Activity 或 Dialog 凭空出现的,一个 Activity 的启动必须要建立在另一个 Activity 的基础之上,也就是以此形成的返回栈。而 Dialog 则必须在一个 Activity 上面弹出(除非是 System Alert 类型的 Dialog),因此在这种场景下,我们只能使用 Activity 类型的 Context,否则将会出错。


getApplicationContext()和 getApplication()方法得到的对象都是同一个 application 对象,只是对象的类型不一样。


Context 数量 = Activity 数量 + Service 数量 + 1 (1 为 Application)

[](

)21.Android 属性动画特性


(1) 对任意对象的属性执行动画操作:属性动画允许对任意对象的属性执行动画操作,因为属性动画的性质是通过反射实现的。


(2)可改变背景颜色。


(3)真正改变 View 本身:因为是通过反射改变其属性,并刷新,如改变 width,他会搜索 getWidth(),反射获取,再通过进行某种计算,将值通过 setWidth()设置进去并更新。

[](

)22.LinearLayout、RelativeLayout、FrameLayout 的特性及对比,并介绍使用场景。


RelativeLayout 的 onMeasure 过程


根据源码我们发现 RelativeLayout 会根据 2 次排列的结果对子 View 各做一次 measure。


首先 RelativeLayout 中子 View 的排列方式是基于彼此的依赖关系,在确定每个子 View 的位置的时候,需要先给所有的子 View 排序一下,所以需要横向纵向分别进行一次排序测量

[](

)23.LinearLayout 的 onMeasure 过程


LinearLayout 会先做一个简单横纵方向判断


需要注意的是在每次对 child 测量完毕后,都会调用 child.getMeasuredHeight()/getMeasuredWidth()获取该子视图最终的高度,并将这个高度添加到 mTotalLength 中。


但是 getMeasuredHeight 暂时避开了 lp.weight>0 且高度为 0 子 View,因为后面会将把剩余高度按 weight 分配给相应的子 View。因此可以得出以下结论:


(1)如果我们在 LinearLayout 中不使用 weight 属性,将只进行一次 measure 的过程。(如果使用 weight 属性,则遍历一次 wiew 测量后,再遍历一次 view 测量)


(2)如果使用了 weight 属性,LinearLayout 在第一次测量时获取所有子 View 的高度,之后再将剩余高度根据 weight 加到 weight>0 的子 View 上。由此可见,weight 属性对性能是有影响的。


1)RelativeLayout 慢于 LinearLayout 是因为它会让子 View 调用 2 次 measure 过程,而 LinearLayout 只需一次,但是有 weight 属性存在时,LinearLayout 也需要两次 measure。


2)在不响应层级深度的情况下,使用 Linearlayout 而不是 RelativeLayout。

[](

)24.谈谈对接口与回调的理解


接口回调就是指: 可以把使用某一接口的类创建的对象的引用赋给该接口声明的接口变量,那么该接口变量就可以调用被类实现的接口的方法。实际上,当接口变量调用被类实现的接口中的方法时,就是通知相应的对象调用接口的方法,这一过程称为对象功能的接口回调。

[](

)25.Android 中 View,SurfaceView 和 GLSurfaceView


View:显示视图,内置画布,提供图形绘制函数,触屏事件,按键事件函数;必须在 UI 线程中更新画面,速度较慢。


SurfaceView:基于 View 视图进行拓展的视图类,更适合 2D 游戏的开发;是 View 的子类,类似双缓机制,在新的线程中更新画面,所以刷新界面速度比 View 快。(双缓机制:即前台缓存和后台缓存,后台缓存计算场景、产生画面,前台缓存显示后台缓存已画好的画面。)


GLSurfaceView:基于 SurfaceView 视图再次进行扩展的视图类,专用于 3D 游戏开发的视图;是 SurfaceView 的子类,OpenGL 专用。(OpenGL:是一个开放的三维图形软件包。)

[](

)26.序列化的作用,以及 Android 两种序列化的区别


作用:java 序列化主要有 2 个作用:


对象持久化,对象生存在内存中,想把一个对象持久化到磁盘,必须已某种方式来组织这个对象包含的信息,这种方式就是序列化;


远程网络通信,内存中的对象不能直接进行网络传输,发送端把对象序列化成网络可传输的字节流,接收端再把字节流还原成对象。


Serializable Java 序列化接口 在硬盘上读写 读写过程中有大量临时变量的生成,内部执行大量的 i/o 操作,效率很低。


Parcelable Android 序列化接口 效率高 使用麻烦 在内存中读写(AS 有相关插件 一键生成所需方法) ,对象不能保存到磁盘中

[](

)27.差值器和估值器


差值器: 根据时间流逝的百分比计算当前属性改变的百分比。


估值器: 根据当前属性改变的百分比计算改变后的属性值

[](

)28.Android 中数据存储方式


1 使用 SharedPreferences 存储数据


适用范围:保存少量的数据,且这些数据的格式非常简单:字符串型、基本类型的值。


比如应用程序的各种配置信息(如是否打开音效等),解锁口 令密码等


核心原理:保存基于 XML 文件存储的 key-value 键值对数据,通常用来存储一些简单的配置信息。


2 文件存储数据


核心原理: Context 提供了两个方法来打开数据文件里的文件 IO 流:


FileInputStream openFileInput(String name);


FileOutputStream openFileOutput(String name , int mode)


3 SQLite 数据库存储数据


4 使用 ContentProvider 存储数据

用户头像

Android架构

关注

还未添加个人签名 2021.10.31 加入

还未添加个人简介

评论

发布
暂无评论
1549页Android最新面试题含答案,成功入职腾讯