写点什么

Android 篇:2019 初中级 Android 开发社招面试解答(上,作为 Android 开发者

用户头像
Android架构
关注
发布于: 2 小时前

Android 篇

Activity

1、说下 Activity 生命周期 ?

  • 参考解答:在正常情况下,Activity 的常用生命周期就只有如下 7 个

  • onCreate():表示 Activity 正在被创建,常用来初始化工作,比如调用 setContentView 加载界面布局资源,初始化 Activity 所需数据等;

  • onRestart():表示 Activity 正在重新启动,一般情况下,当前 Acitivty 从不可见重新变为可见时,OnRestart 就会被调用;

  • onStart():表示 Activity 正在被启动,此时 Activity 可见但不在前台,还处于后台,无法与用户交互;

  • onResume():表示 Activity 获得焦点,此时 Activity 可见且在前台并开始活动,这是与 onStart 的区别所在;

  • onPause():表示 Activity 正在停止,此时可做一些存储数据、停止动画等工作,但是不能太耗时,因为这会影响到新 Activity 的显示,onPause 必须先执行完,新 Activity 的 onResume 才会执行;

  • onStop():表示 Activity 即将停止,可以做一些稍微重量级的回收工作,比如注销广播接收器、关闭网络连接等,同样不能太耗时;

  • onDestroy():表示 Activity 即将被销毁,这是 Activity 生命周期中的最后一个回调,常做回收工作、资源释放

  • 延伸:从整个生命周期来看,onCreate 和 onDestroy 是配对的,分别标识着 Activity 的创建和销毁,并且只可能有一次调用; 从 Activity 是否可见来说,onStart 和 onStop 是配对的,这两个方法可能被调用多次; 从 Activity 是否在前台来说,onResume 和 onPause 是配对的,这两个方法可能被调用多次; 除了这种区别,在实际使用中没有其他明显区别;

2、Activity A 启动另一个 Activity B 会调用哪些方法?如果 B 是透明主题的又或则是个 DialogActivity 呢 ?

  • 参考解答:Activity A 启动另一个 Activity B,回调如下

  • Activity A 的 onPause() → Activity B 的 onCreate() → onStart() → onResume() → Activity A 的 onStop();

  • 如果 B 是透明主题又或则是个 DialogActivity,则不会回调 A 的 onStop;

3、说下 onSaveInstanceState()方法的作用 ? 何时会被调用?

  • 参考解答:发生条件:异常情况下(系统配置发生改变时导致 Activity 被杀死并重新创建、资源内存不足导致低优先级的 Activity 被杀死

  • 系统会调用 onSaveInstanceState 来保存当前 Activity 的状态,此方法调用在 onStop 之前,与 onPause 没有既定的时序关系;

  • 当 Activity 被重建后,系统会调用 onRestoreInstanceState,并且把 onSave(简称)方法所保存的 Bundle 对象同时传参给 onRestore(简称)和 onCreate(),因此可以通过这两个方法判断 Activity 是否被重建,调用在 onStart 之后;


  • 推荐文章:

  • 官方文档

4、说下 Activity 的四种启动模式、应用场景 ?

  • 参考回答:

  • standard 标准模式:每次启动一个 Activity 都会重新创建一个新的实例,不管这个实例是否已经存在,此模式的 Activity 默认会进入启动它的 Activity 所属的任务栈中;

  • singleTop 栈顶复用模式:如果新 Activity 已经位于任务栈的栈顶,那么此 Activity 不会被重新创建,同时会回调 onNewIntent 方法,如果新 Activity 实例已经存在但不在栈顶,那么 Activity 依然会被重新创建;

  • singleTask 栈内复用模式:只要 Activity 在一个任务栈中存在,那么多次启动此 Activity 都不会重新创建实例,并回调 onNewIntent 方法,此模式启动 Activity A,系统首先会寻找是否存在 A 想要的任务栈,如果不存在,就会重新创建一个任务栈,然后把创建好 A 的实例放到栈中;

  • singleInstance 单实例模式:这是一种加强的 singleTask 模式,具有此种模式的 Activity 只能单独地位于一个任务栈中,且此任务栈中只有唯一一个实例;

  • 推荐文章:

  • 官方文档

5、了解哪些 Activity 常用的标记位 Flags?

  • 参考回答:

  • FLAG_ACTIVITY_NEW_TASK : 对应 singleTask 启动模式,其效果和在 XML 中指定该启动模式相同;

  • FLAG_ACTIVITY_SINGLE_TOP : 对应 singleTop 启动模式,其效果和在 XML 中指定该启动模式相同;

  • FLAG_ACTIVITY_CLEAR_TOP : 具有此标记位的 Activity,当它启动时,在同一个任务栈中所有位于它上面的 Activity 都要出栈。这个标记位一般会和 singleTask 模式一起出现,在这种情况下,被启动 Activity 的实例如果已经存在,那么系统就会回调 onNewIntent。如果被启动的 Activity 采用 standard 模式启动,那么它以及连同它之上的 Activity 都要出栈,系统会创建新的 Activity 实例并放入栈中;

  • FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS : 具有这个标记的 Activity 不会出现在历史 Activity 列表中;

  • 推荐文章:

  • 官方文档

6、说下 Activity 跟 window,view 之间的关系?

  • 参考回答:

  • Activity 在创建时会调用 attach() 方法初始化一个 PhoneWindow(继承于 Window)每一个 Activity 都包含了唯一一个 PhoneWindow

  • Activity 通过 setContentView 实际上是调用的 getWindow().setContentView 将 View 设置到 PhoneWindow 上,而 PhoneWindow 内部是通过 WindowManageraddViewremoveViewupdateViewLayout 这三个方法来管理 View,WindowManager 本质是接口,最终由 WindowManagerImpl 实现

  • 延伸

  • WindowManager 为每个 Window 创建 Surface 对象,然后应用就可以通过这个 Surface 来绘制任何它想要绘制的东西。而对于 WindowManager 来说,这只不过是一块矩形区域而已

  • Surface 其实就是一个持有像素点矩阵的对象,这个像素点矩阵是组成显示在屏幕的图像的一部分。我们看到显示的每个 Window(包括对话框、全屏的 Activity、状态栏等)都有他自己绘制的 Surface。而最终的显示可能存在 Window 之间遮挡的问题,此时就是通过 SurfaceFlinger 对象渲染最终的显示,使他们以正确的 Z-order 显示出来。一般 Surface 拥有一个或多个缓存(一般 2 个),通过双缓存来刷新,这样就可以一边绘制一边加新缓存。

  • View Window 里面用于交互的 UI 元素。Window attach 一个 View Tree(组合模式),当 Window 需要重绘(如,当 View 调用 invalidate)时,最终转为 Window SurfaceSurface 被锁住(locked)并返回 Canvas 对象,此时 View 拿到 Canvas 对象来绘制自己。当所有 View 绘制完成后,Surface 解锁(unlock),并且 post 到绘制缓存用于绘制,通过 Surface Flinger 来组织各个 Window,显示最终的整个屏幕

  • 推荐文章:

  • Activity、View、Window的理解一篇文章就够了

7、横竖屏切换的 Activity 生命周期变化?

  • 参考回答:

  • 不设置 Activity 的 android:configChanges 时,切屏会销毁当前 Activity,然后重新加载调用各个生命周期,切横屏时会执行一次,切竖屏时会执行两次; onPause() →onStop()→onDestory()→onCreate()→onStart()→onResume()

  • 设置 Activity 的 android:configChanges="orientation",经过机型测试

  • 在 Android5.1 即 API 23 级别下,切屏还是会重新调用各个生命周期,切横、竖屏时只会执行一次

  • 在 Android9 即 API 28 级别下,切屏不会重新调用各个生命周期,只会执行 onConfigurationChanged 方法

  • 后经官方查正,原话如下

  • 如果您的应用面向 Android 3.2 即 API 级别 13 或更高级别(按照 minSdkVersion 和 targetSdkVersion 属性所声明的级别),则还应声明 "screenSize" 配置,因为当设备在横向与纵向之间切换时,该配置也会发生变化。即便是在 Android 3.2 或更高版本的设备上运行,此配置变更也不会重新启动 Activity

  • 设置 Activity 的 android:configChanges="orientation|keyboardHidden|screenSize"时,机型测试通过,切屏不会重新调用各个生命周期,只会执行 onConfigurationChanged 方法;

  • 推荐文章:

  • Android 横竖屏切换加载不同的布局

8、如何启动其他应用的 Activity?

  • 参考回答:

  • 在保证有权限访问的情况下,通过隐式 Intent 进行目标 Activity 的 IntentFilter 匹配,原则是:

  • 一个 intent 只有同时匹配某个 Activity 的 intent-filter 中的 action、category、data 才算完全匹配,才能启动该 Activity;

  • 一个 Activity 可以有多个 intent-filter,一个 intent 只要成功匹配任意一组 intent-filter,就可以启动该 Activity;

  • 推荐文章:

  • action、category、data的具体匹配规则

9、Activity 的启动过程?(重点)

  • 参考回答:

  • ?先还是得当前系统中有没有拥有这个 Application 的进程。如果没有,则需要处理 APP 的启动过 程。在经过创建进程、绑定 Application 步骤后,才真正开始启动 Activity 的?法。 startActivity() ? 法最终还是调?的 startActivityForResult()。

  • 在 startActivityForResult() 中,真正去打开 Activity 的实现是在 Instrumentation 的 execStartActivivity() ?法中。

  • 在 execStartActivity() 中采? checkStartActivityResult() 检查在 manifest 中是否已经注册,如果没 有注册则抛出异常。否则把打开 Activity 的任务交给 ActivityThread 的内部类 ApplicationThread, 该类实现了 IApplicationThread 接?。这个类完全搞定了 onCreate()、onStart() 等 Activity 的?命 周期回调?法。

  • 在 ApplicationThread 类中,有?个?法叫 scheduleLaunchActivity(),它可以构造?个 Activity 记 录,然后发送?个消息给事先定义好的 Handler。 这个 Handler 负责根据 LAUNCH_ACTIVITY 的类型来做不同的 Activity 启动?式。其中有?个?要的 ?法 handleLaunchActivity() 。

  • 在 handleLaunchActivity() 中,会把启动 Activity 交给 performLaunchActivity() ?法。 在 performLaunchActivity() ?法中,?先从 Intent 中解析出?标 Activity 的启动参数,然后? ClassLoader 将?标 Activity 的类通过类名加载出来并? newInstance() 来实例化?个对象。 创建完毕后, 开始调? Activity 的 onCreate() ?法,?此,Activity 被成功启动。


  • 推荐文章:

  • Android四大组件启动机制之Activity启动过程

Fragment

1、谈一谈 Fragment 的生命周期?

  • 参考回答:

  • Fragment 从创建到销毁整个生命周期中涉及到的方法依次为:onAttach()→onCreate()→ onCreateView()→onActivityCreated()→onStart()→onResume()→onPause()→onStop()→onDestroyView()→onDestroy()→onDetach(),其中和 Activity 有不少名称相同作用相似的方法,而不同的方法有:

  • onAttach():当 Fragment 和 Activity 建立关联时调用;

  • onCreateView():当 fragment 创建视图调用,在 onCreate 之后;

  • onActivityCreated():当与 Fragment 相关联的 Activity 完成 onCreate()之后调用;

  • onDestroyView():在 Fragment 中的布局被移除时调用;

  • onDetach():当 Fragment 和 Activity 解除关联时调用;

  • 推荐文章:

  • Android之Fragment优点

2、谈谈 Activity 和 Fragment 的区别?

  • 参考回答:

  • 相似点:都可包含布局、可有自己的生命周期

  • 不同点:

  • Fragment 相比较于 Activity 多出 4 个回调周期,在控制操作上更灵活;

  • Fragment 可以在 XML 文件中直接进行写入,也可以在 Activity 中动态添加;

  • Fragment 可以使用 show()/hide()或者 replace()随时对 Fragment 进行切换,并且切换的时候不会出现明显的效果,用户体验会好;Activity 虽然也可以进行切换,但是 Activity 之间切换会有明显的翻页或者其他的效果,在小部分内容的切换上给用户的感觉不是很好;

3、Fragment 中 add 与 replace 的区别(Fragment 重叠)

  • 参考回答:

  • add 不会重新初始化 fragment,replace 每次都会。所以如果在 fragment 生命周期内获取获取数据,使用 replace 会重复获取;

  • 添加相同的 fragment 时,replace 不会有任何变化,add 会报 IllegalStateException 异常;

  • replace 先 remove 掉相同 id 的所有 fragment,然后在 add 当前的这个 fragment,而 add 是覆盖前一个 fragment。所以如果使用 add 一般会伴随 hide()和 show(),避免布局重叠;

  • 使用 add,如果应用放在后台,或以其他方式被系统销毁,再打开时,hide()中引用的 fragment 会销毁,所以依然会出现布局重叠 bug,可以使用 replace 或使用 add 时,添加一个 tag 参数;


4、getFragmentManager、getSupportFragmentManager 、getChildFragmentManager 之间的区别?

  • 参考回答:

  • getFragmentManager()所得到的是所在 fragment 的父容器的管理器, getChildFragmentManager()所得到的是在 fragment 里面子容器的管理器, 如果是 fragment 嵌套 fragment,那么就需要利用 getChildFragmentManager();

  • 因为 Fragment 是 3.0 Android 系统 API 版本才出现的组件,所以 3.0 以上系统可以直接调用 getFragmentManager()来获取 FragmentManager()对象,而 3.0 以下则需要调用 getSupportFragmentManager() 来间接获取;

5、FragmentPagerAdapter 与 FragmentStatePagerAdapter 的区别与使用场景

  • 参考回答:

  • 相同点 :二者都继承 PagerAdapter

  • 不同点 :FragmentPagerAdapter 的每个 Fragment 会持久的保存在 FragmentManager 中,只要用户可以返回到页面中,它都不会被销毁。因此适用于那些数据相对静态的页,Fragment 数量也比较少的那种; **Fra


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


gmentStatePagerAdapter 只保留当前页面,当页面不可见时,该 Fragment 就会被消除,释放其资源。因此适用于那些数据动态性**较大、占用内存较多,多 Fragment 的情况;

Service

1、谈一谈 Service 的生命周期?

  • 参考回答:Service 的生命周期涉及到六大方法

  • onCreate():如果 service 没被创建过,调用 startService()后会执行 onCreate()回调;如果 service 已处于运行中,调用 startService()不会执行 onCreate()方法。也就是说,onCreate()只会在第一次创建 service 时候调用,多次执行 startService()不会重复调用 onCreate(),此方法适合完成一些初始化工作;

  • onStartComand():服务启动时调用,此方法适合完成一些数据加载工作,比如会在此处创建一个线程用于下载数据或播放音乐;

  • onBind():服务被绑定时调用;

  • onUnBind():服务被解绑时调用;

  • onDestroy():服务停止时调用;

  • 推荐文章:

  • Android组件系列----Android Service组件深入解析

2、Service 的两种启动方式?区别在哪?

  • 参考回答:Service 的两种启动模式

  • startService():通过这种方式调用 startService,onCreate()只会被调用一次,多次调用 startSercie 会多次执行 onStartCommand()和 onStart()方法。如果外部没有调用 stopService()或 stopSelf()方法,service 会一直运行。

  • bindService():如果该服务之前还没创建,系统回调顺序为 onCreate()→onBind()。如果调用 bindService()方法前服务已经被绑定,多次调用 bindService()方法不会多次创建服务及绑定。如果调用者希望与正在绑定的服务解除绑定,可以调用 unbindService()方法,回调顺序为 onUnbind()→onDestroy();


  • 推荐文章:

  • Android Service两种启动方式详解

3、如何保证 Service 不被杀死 ?

  • 参考回答:

  • onStartCommand 方式中,返回 START_STICKY 或则 START_REDELIVER_INTENT

  • START_STICKY:如果返回 START_STICKY,表示 Service 运行的进程被 Android 系统强制杀掉之后,Android 系统会将该 Service 依然设置为 started 状态(即运行状态),但是不再保存 onStartCommand 方法传入的 intent 对象

  • START_NOT_STICKY:如果返回 START_NOT_STICKY,表示当 Service 运行的进程被 Android 系统强制杀掉之后,不会重新创建该 Service

  • START_REDELIVER_INTENT:如果返回 START_REDELIVER_INTENT,其返回情况与 START_STICKY 类似,但不同的是系统会保留最后一次传入 onStartCommand 方法中的 Intent 再次保留下来并再次传入到重新创建后的 Service 的 onStartCommand 方法中

  • 提高 Service 的优先级 在 AndroidManifest.xml 文件中对于 intent-filter 可以通过 android:priority = "1000"这个属性设置最高优先级,1000 是最高值,如果数字越小则优先级越低,同时适用于广播;

  • 在 onDestroy 方法里重启 Service 当 service 走到 onDestroy()时,发送一个自定义广播,当收到广播时,重新启动 service;

  • 提升 Service 进程的优先级 进程优先级由高到低:前台进程 一 可视进程 一 服务进程 一 后台进程 一 空进程 可以使用 startForeground 将 service 放到前台状态,这样低内存时,被杀死的概率会低一些;

  • 系统广播监听 Service 状态

  • 将 APK 安装到/system/app,变身为系统级应用

  • 注意:以上机制都不能百分百保证 Service 不被杀死,除非做到系统白名单,与系统同生共死

4、能否在 Service 开启耗时操作 ? 怎么做 ?

  • 参考回答:

  • Service 默认并不会运行在子线程中,也不运行在一个独立的进程中,它同样执行在主线程中(UI 线程)。换句话说,不要在 Service 里执行耗时操作,除非手动打开一个子线程,否则有可能出现主线程被阻塞(ANR)的情况;

5、用过哪些系统 Service ?

  • 参考回答:


6、了解 ActivityManagerService 吗?发挥什么作用

  • 参考回答: ActivityManagerService 是 Android 中最核心的服务 , 主要负责系统中四大组件的启动、切换、调度及应用进程的管理和调度等工作,其职责与操作系统中的进程管理和调度模块类似;

  • 推荐文章:

  • ActivityManagerService分析——AMS启动流程

Broadcast Receiver

1、广播有几种形式 ? 都有什么特点 ?

  • 参考回答:

  • 普通广播:开发者自身定义 intent 的广播(最常用),所有的广播接收器几乎会在同一时刻接受到此广播信息,接受的先后顺序随机

  • 有序广播:发送出去的广播被广播接收者按照先后顺序接收,同一时刻只会有一个广播接收器能够收到这条广播消息,当这个广播接收器中的逻辑执行完毕后,广播才会继续传递,且优先级(priority)高的广播接收器会先收到广播消息。有序广播可以被接收器截断使得后面的接收器无法收到它;

  • 本地广播:仅在自己的应用内发送接收广播,也就是只有自己的应用能收到,数据更加安全,效率更高,但只能采用动态注册的方式;

  • 粘性广播:这种广播会一直滞留,当有匹配该广播的接收器被注册后,该接收器就会收到此条广播;

  • 推荐文章:

  • Android四大组件:BroadcastReceiver史上最全面解析

2、广播的两种注册方式 ?

  • 参考回答:


3、广播发送和接收的原理了解吗 ?(Binder 机制、AMS)

ContentProvider

1、ContentProvider 了解多少?

  • 参考回答:

  • ContentProvider 作为四大组件之一,其主要负责存储和共享数据。与文件存储、SharedPreferences 存储、SQLite 数据库存储这几种数据存储方法不同的是,后者保存下的数据只能被该应用程序使用,而前者可以让不同应用程序之间进行数据共享,它还可以选择只对哪一部分数据进行共享,从而保证程序中的隐私数据不会有泄漏风险。

  • 推荐文章:

  • Android:关于ContentProvider的知识都在这里了!

2、ContentProvider 的权限管理?

  • 参考回答:

  • 读写分离

  • 权限控制-精确到表级

  • URL 控制

3、说说 ContentProvider、ContentResolver、ContentObserver 之间的关系?

  • 参考回答:

  • ContentProvider:管理数据,提供数据的增删改查操作,数据源可以是数据库、文件、XML、网络等,ContentProvider 为这些数据的访问提供了统一的接口,可以用来做进程间数据共享。

  • ContentResolver:ContentResolver 可以为不同 URI 操作不同的 ContentProvider 中的数据,外部进程可以通过 ContentResolver 与 ContentProvider 进行交互。

  • ContentObserver:观察 ContentProvider 中的数据变化,并将变化通知给外界。

数据存储

1、描述一下 Android 数据持久存储方式?

  • 参考回答:Android 平台实现数据持久存储的常见几种方式:

  • SharedPreferences 存储:一种轻型的数据存储方式,本质是基于 XML 文件存储的 key-value 键值对数据,通常用来存储一些简单的配置信息(如应用程序的各种配置信息);

  • SQLite 数据库存储:一种轻量级嵌入式数据库引擎,它的运算速度非常快,占用资源很少,常用来存储大量复杂的关系数据;

  • ContentProvider:四大组件之一,用于数据的存储和共享,不仅可以让不同应用程序之间进行数据共享,还可以选择只对哪一部分数据进行共享,可保证程序中的隐私数据不会有泄漏风险;

  • File 文件存储:写入和读取文件的方法和 Java 中实现 I/O 的程序一样;

  • 网络存储:主要在远程的服务器中存储相关数据,用户操作的相关数据可以同步到服务器上;

2、SharedPreferences 的应用场景?注意事项?

  • 参考回答:

  • SharedPreferences 是一种轻型的数据存储方式,本质是基于 XML 文件存储的 key-value 键值对数据,通常用来存储一些简单的配置信息,如 int,String,boolean、float 和 long;

  • 注意事项:

  • 勿存储大型复杂数据,这会引起内存 GC、阻塞主线程使页面卡顿产生 ANR

  • 勿在多进程模式下,操作 Sp

  • 不要多次 edit 和 apply,尽量批量修改一次提交

  • 建议 apply,少用 commit


3、SharedPrefrences 的 apply 和 commit 有什么区别?

  • 参考回答:

  • apply 没有返回值而 commit 返回 boolean 表明修改是否提交成功。

  • apply 是将修改数据原子提交到内存, 而后异步真正提交到硬件磁盘, 而 commit 是同步的提交到硬件磁盘,因此,在多个并发的提交 commit 的时候,他们会等待正在处理的 commit 保存到磁盘后在操作,从而降低了效率。而 apply 只是原子的提交到内容,后面有调用 apply 的函数的将会直接覆盖前面的内存数据,这样从一定程度上提高了很多效率。

  • apply 方法不会提示任何失败的提示。 由于在一个进程中,sharedPreference 是单实例,一般不会出现并发冲突,如果对提交的结果不关心的话,建议使用 apply,当然需要确保提交成功且有后续操作的话,还是需要用 commit 的。

4、了解 SQLite 中的事务操作吗?是如何做的

  • 参考回答:

  • SQLite 在做 CRDU 操作时都默认开启了事务,然后把 SQL 语句翻译成对应的 SQLiteStatement 并调用其相应的 CRUD 方法,此时整个操作还是在 rollback journal 这个临时文件上进行,只有操作顺利完成才会更新 db 数据库,否则会被回滚;

5、使用 SQLite 做批量操作有什么好的方法吗?

  • 参考回答:

  • 使用 SQLiteDatabase 的 beginTransaction 方法开启一个事务,将批量操作 SQL 语句转化为 SQLiteStatement 并进行批量操作,结束后 endTransaction()

6、如何删除 SQLite 中表的个别字段

  • 参考回答:

  • SQLite 数据库只允许增加字段而不允许修改和删除表字段,只能创建新表保留原有字段,删除原表

7、使用 SQLite 时会有哪些优化操作?

  • 参考回答:

  • 使用事务做批量操作

  • 及时关闭 Cursor,避免内存泄露

  • 耗时操作异步化:数据库的操作属于本地 IO 耗时操作,建议放入异步线程中处理

  • ContentValues 的容量调整:ContentValues 内部采用 HashMap 来存储 Key-Value 数据,ContentValues 初始容量为 8,扩容时翻倍。因此建议对 ContentValues 填入的内容进行估量,设置合理的初始化容量,减少不必要的内部扩容操作

  • 使用索引加快检索速度:对于查询操作量级较大、业务对查询要求较高的推荐使用索引

IPC

1、Android 中进程和线程的关系? 区别?

用户头像

Android架构

关注

还未添加个人签名 2021.10.31 加入

还未添加个人简介

评论

发布
暂无评论
Android篇:2019初中级Android开发社招面试解答(上,作为Android开发者