Android开发Android开发经验谈Android开发

「 Android面试题集 」—— Android四大组件,这

2020-09-15  本文已影响0人  程序员叁柒

前言

虽然有很多面试的文章里都有这些题目,但是我每次在看的时候,总是会觉得有些分散,在准备面试复习的时候还要重新去找到对应的文章和学习资料,所以我就想着自己来整理一下,并且把题目给分一下类型;自己整理可以帮助我复习的同时还可以巩固一遍;

这次主要是Android四大组件面试题相关Android其余面试热门知识点已整理成PDF版,后面会按知识点分类分享

需要免费获取完整「Android面试题集」(高清PDF版)的朋友————(此处免费打包领取)觉得有帮助、有需要的可以点个赞

Android面试题集 PDF版
Android面试题集 PDF版

一、Activity

1、描述一下Activity 生命周期?

生命周期:为了巩固记忆,画了一遍。

Activity之间跳转时的生命周期

2、A Activity 打开 B Activity 时都有哪些生命周期回调?

A.onPause -> B.onCrete -> B.onStart -> B.onResume -> A.onStop

这样回答只是及格,因为仅在 B Activity 的 launchMode 为 standard 或者 B Activity 没有可复用的实例时是这样的。

当 B Activity 的 launchMode 为 singleTop 且 B Activity 已经在栈顶时(一些特殊情况如通知栏点击、连点),此时只有 B 页面自己有生命周期变化:

B.onPause -> B.onNewIntent -> B.onResume

当 B Activity 的 launchMode 为 singleInstance ,singleTask 且对应的 B Activity 有可复用的实例时,生命周期回调是这样的:

A.onPause -> B.onNewIntent -> B.onRestart -> B.onStart -> B.onResume -> A.onStop -> ( 如果 A 被移出栈的话还有一个 A.onDestory)

Activity的启动模式

有4种启动模式:

standard 标准模式singleTop 栈顶复用模式singleTask 栈内复用模式singleInstance 单例模式
标准模式:每次启动时,都会创建一个新的实例在栈顶

栈顶复用模式:如果需要新创建的实例就在栈顶,那么就不会去重建,而是重用,否则就重新创建。

栈内复用模式:如果实例在当前栈中已经存在,就会将当前实例上面的其他实例都移除栈。

单例模式:直接创建一个新的栈并且创建实例放在栈中。

使用方式:
1.可以在在AndroidMainifest的Activity配置进行设置:android:launchMode="启动模式"
2.通过 Intent设置标志位

val intent=Intent(this,SocendActivity::class.java)
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
startActivity(intent)
//其中标志位属性
FLAGACTIVITYSINGLE_TOP:指定启动模式为栈顶复用模式( SingleTop)
FLAGACTIVITYNEW_TASK: 指定启动模式为栈内复用模式( SingleTask)
FLAGACTIVITYCLEAR_TOP:所有位于其上层的Activity都要移除, SingleTask模式默认具有此标记效果
FLAGACTIVITYEXCLUDEFROMRECENTS:具有该标记的Activity不会出现在历史Activity的列表中,即无法通过历史列表回到该Activity上

那么这两种方式有什么区别呢?

优先级不同 Intent设置方式的优先级 > Manifest设置方式,即 以前者为准限定范围不同 Manifest设置方式无法设定 FLAG_ACTIVITY_CLEAR_TOP; Intent设置方式 无法设置单例模式( SingleInstance)

onStart,onStop和onResume,onPause的区别?

Activity的生命周期中,大部分都是两两相对的,可以将其分为3种,前台,可见,后台。
onStart,onStop之间所经历的是可见的,但是却可能无法与用户交互。
onResume,onPause之间所经历的是属于前台,这时候用户是可以交互的。

如果新Activity是透明主题时,旧Activity会不会走onStop?

不会!
锁定屏与解锁屏幕,Activity如何执行生命周期的?
锁屏时只会调用onPause(),而不会调用onStop方法,开屏后则调用onResume()。

横竖屏切换时的生命周期?

如果清单文件中没有设置android:configChanges属性时,生命周期:先销毁onPause()、onStop()、onDestroy()再重新创建onCreate()、onStart()、onResume()方法。
设置orientation|screenSize(一定要同时出现)属性值时,不走生命周期方法,只会执行onConfigurationChanged()方法。

弹出 Dialog 对生命周期有什么影响?

我们知道,生命周期回调都是 AMS 通过 Binder 通知应用进程调用的;而弹出 Dialog、Toast、PopupWindow 本质上都直接是通过 WindowManager.addView() 显示的(没有经过 AMS),所以不会对生命周期有任何影响。
如果是启动一个 Theme 为 Dialog 的 Activity , 则生命周期为:
A.onPause -> B.onCrete -> B.onStart -> B.onResume
注意:这边没有前一个 Activity 不会回调 onStop,因为只有在 Activity 切到后台不可见才会回调 onStop;而弹出 Dialog 主题的 Activity 时前一个页面还是可见的,只是失去了焦点而已所以仅有 onPause 回调。

Activity 在 onResume 之后才显示的原因是什么?

虽然我们设置 Activity 的布局一般都是在 onCreate 方法里调用 setContentView 。里面是直接调用 window 的 setContentView,创建一个 DecorView 用来包住我们创建的布局。详情如下:

PhoneWindow.java
public void setContentView(int layoutResID) {
    if (mContentParent == null) {
        installDecor();
    } 
    ...
    // 加载布局,添加到 mContentParent
    // mContentParent 又是 DecorView 的一个子布局  
    mLayoutInflater.inflate(layoutResID, mContentParent);
}

然而这一步只是加载好了布局,生成一个 ViewTree , 具体怎么把 ViewTree 显示出来,答案就在下面:

ActivityThread.java
public void handleResumeActivity(...){
    // onResume 回调
    ActivityClientRecord r = performResumeActivity(...)
    final Activity a = r.activity;
    if (r.window == null && !a.mFinished && willBeVisible) {
        r.window = r.activity.getWindow();
        View decor = r.window.getDecorView();
        ViewManager wm = a.getWindowManager();
        wm.addView(decor, l);// 重点
    }
}

WindowManager 的 addView 方法最终将 DecorView 添加到 WMS ,实现绘制到屏幕、接收触屏事件。具体的调用链如下:

   WindowManagerImpl.addView
-> WindowManagerGlobal.addView
-> ViewRootImpl.setView     
-> ViewRootImpl.requestLayout() // 执行 View 的绘制流程
   // 通过 Binder 调用 WMS ,WMS 会添加一个 Window 相关的对象
   // 应用端通过 mWindowSession 调用 WMS
   // WMS 通过 mWindow (一个 Binder 对象) 调用应用端  
   mWindowSession.addToDisplay(mWindow) 

综上,在onResume回调之后,会创建一个 ViewRootImpl ,有了它之后应用端就可以和 WMS 进行双向调用了。

onActivityResult 在哪两个生命周期之间回调?

onActivityResult 不属于 Activity 的生命周期,一般被问到这个问题时大家都会懵逼。

其实答案很简单,onActivityResult 方法的注释中就写着答案:
「You will receive this call immediately before onResume() when your activity is re-starting.」
跟一下代码(TransactionExecutor.execute 有兴趣的可以自己打断点跟一下),会发现 onActivityResult 回调先于该 Activity 的所有生命周期回调,从 B Activity 返回 A Activity 的生命周期调用为:
B.onPause -> A.onActivityResult -> A.onRestart -> A.onStart -> A.onResume

onCreate 方法里写死循环会 ANR 吗?

ANR 的四种场景:

Service TimeOut: service 未在规定时间执行完成:前台服务 20s,后台 200s

BroadCastQueue TimeOut: 未在规定时间内未处理完广播:前台广播 10s 内, 后台 60s 内

ContentProvider TimeOut: publish 在 10s 内没有完成

Input Dispatching timeout: 5s 内未响应键盘输入、触摸屏幕等事件

我们可以看到,Activity 的生命周期回调的阻塞并不在触发 ANR 的场景里面,所以并不会直接触发 ANR。
只不过死循环阻塞了主线程,如果系统再有上述的四种事件发生,就无法在相应的时间内处理从而触发 ANR。

onNewIntent是什么时候调用的?

如果需要启动的实例是之前有打开过的,并且在栈的顶部,目前处于onPause、onStop 的状态,其他实例再次进入的话,执行顺序为:onNewIntent,onRestart,onStart,onResume。

onSaveInstanceState()方法的作用?
异常情况下系统配置发生改变时导致Activity被杀死并重新创建、资源内存不足导致低优先级的Activity被杀死

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

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

1、点击桌面App图标,Launcher进程采用Binder IPC向system_server进程发起startActivity请求;
2、system_server进程接收到请求后,向zygote进程发送创建进程的请求;
3、Zygote进程fork出新的子进程,即App进程;
4、App进程,通过Binder IPC向sytem_server进程发起attachApplication请求;
5、system_server进程在收到请求后,进行一系列准备工作后,再通过binder IPC向App进程发送scheduleLaunchActivity请求;
6、App进程的binder线程(ApplicationThread)在收到请求后,通过handler向主线程发送LAUNCH_ACTIVITY消息;
7、主线程在收到Message后,通过发射机制创建目标Activity,并回调Activity.onCreate()等方法。

启动过程时序图

Fragment

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解除关联时调用;

Activity和Fragment的区别?

相同:

都可包含布局、可有自己的生命周期

不相同:

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

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

Fragment中add与replace的区别?

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时,判断是否已经添加过。

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

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

FragmentPagerAdapter与FragmentStatePagerAdapter的区别与使用场景?

相同:

二者都继承PagerAdapter

不同:

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

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

Service

什么是Service?

有需求需要APP在后台运行时,Service就是一个这样的入口,Service是一种可以在后台执行长时间运行操作而没有用户界面的应用组件,后台服务于Activity,封装有一个完整的功能逻辑实现,接受上层指令,完成相关的事务,定义好需要接受的Intent提供同步和异步的接口。

Service的生命周期

<figcaption style="margin-top: 5px; text-align: center; color: #888; display: block; font-size: 12px; font-family: PingFangSC-Light;">生命周期</figcaption>

Service的启动方式?如果启动方式交织在一起的话,会出现什么情况?

Service 有绑定模式和非绑定模式,以及这两种模式的混合使用方式。不同的使用方法生命周期方法也不同。

上面的两种生命周期是在相对单纯的模式下的情形。注意 Service 实例只会有一个,也就是说如果当前要启动的 Service 已经存在了那么就不会再次创建该 Service 当然也不会调用 onCreate()方法。

在startService中
步骤:
1、定义一个类继承于Service
2、在Manifest.xml文件中配置该Service
3、使用Context的startService(Intent)方法启动该Service
4、不再使用时使用stopService(Intent)方法停止该服务

每次通过startService(Intent)方法启动Service时都会调用。其中我们可以注意onStartCommand是有返回值的。

在bindService中
步骤:
1、定义一个类继承Service,创建一个继承与Binder的实例对象,并提供公共方法供客户端调用。
2、实现onBind()方法,返回Binder实例
3、在Manifest.xml文件中配置该Service
4、在客户端中,实现ServiceConnection实例,从onServiceConnected()回调方法接收Binder,并使用bindService绑定服务。
注:onServiceDiscounnection方法是在服务崩溃或者服务杀死导致的连接中断时调用

首先会调用onCreate,然后调用onBind方法,然后在Activity与Service解绑时调用Unbind方法,最后在所有Activity与Service解绑后,该Service会销毁,并调用onDestroy方法。 onBind:绑定服务才会调用,但注意即使我们用startService也要实现该方法。
一个 Service 可以被多个客户进行绑定,只有所有的绑定对象都执行了onBind()方法后该 Service 才会销毁,不过如果有一个客户执行了 onStart()方法,那么这个时候如果所有的 bind 客户都执行了 unBind()该 Service 也不会销毁。

混合使用
在这之前,要知道一个原则是 Service 的 onCreate 的方法只会被调用一次,就是你无论多少次的startService又bindService,Service只被创建一次。

混合使用时的生命周期

Service中可以弹Toast吗?

可以,弹吐司有个条件就是得有一个 Context 上下文,而 Service 本身就是 Context 的子类,因此在 Service 里面弹吐司是完全可以的。

如何在 service 中执行网络操作?

可以直接在Service中onStartCommand()方法中可以执行网络操作,service 里面不能执行耗时的操作(网络请求,拷贝数据库,大文件 ),如果需要在服务中进行耗时操作,可以选择IntentService, IntentService是Service的子类,用来处理异步请求。

什么是IntentService?

IntentService 是 Service 的子类,比普通的 Service 增加了额外的功能。

IntentService的特征

Service 和 Activity 在同一个线程吗?

在一个app的情况下,默认是在同一个线程中的,main Thread (UI Thread)。

Service和Thread的区别?

Thread是程序运行的最小单元——线程。
Service是安卓的一种机制,运行在主线程,因此在Service中进行耗时操作也需要开启新的线程。 那为什么还要Service不在Activity中直接操作Thread呢? 因为activity很难对Thread进行管理,当activity销毁了,之后的activity就没办法获取到之前创建的Thread。

如何提高service的优先级?

进程的重要性依次是:前台进程、可见进程、服务进程、后台进程、空进程。所以销毁的顺序为逆方向。

Activity、Intent、Service 是什么关系?

他们都是 Android 开发中使用频率最高的类。其中 Activity 和 Service 都是 Android 四大组件之一。都是 Context 类的子类 ContextWrapper 的子类, 因此他俩可以算是兄弟关系吧。不过兄弟俩各有各自的本领,Activity 负责用户界面的显示和交互,Service 负责后台任务的处理。Activity 和 Service 之间可 以通过 Intent 传递数据,因此可以把 Intent 看作是通信使者。

ActivityManagerService了解吗?有什么作用?

ActivityManagerService是Android中最核心的服务,主要负责系统中四大组件的启动、切换、调度及应用进程的管理和调度等工作,其职责与操作系统中的进程管理和调度模块类似; 初识AMS,感兴趣可以看一下

BroadcastReceiver

这是一种让系统在正常的用户流之外,传递事件给APP的机制,BroadcastReceiver也就是“广播接收者”的意思,顾名思义,它就是用来接收来自系统和应用中的广播。

广播类型有几种?
广播的两种注册方式有什么区别?
广播发送和接收的步骤是什么?原理了解吗?

ContentProvider

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

ContentProvider 是如何实现数据共享的?

在 Android 中如果想将自己应用的数据(一般多为数据库中的数据)提供 给第三发应用,那么我们只能通过 ContentProvider 来实现。ContentProvider 是应用程序之间共享数据的接口。使用的时候首先自定义一个类继承ContentProvider,然后覆写 query、insert、update、delete 等方法。因为其是四大组件之一因此必须在 AndroidManifest 文件中进行注册,把自己的数据通过 uri 的形式共享出去 。

ContentProvider、ContentResolver、ContentObserver 之间的关系?

另外,现在到了“金九银十跳槽期”了,有不少朋友都想在这个时期跳槽升职涨工资了,个人建议在面试之前给自己做一次完整的知识梳理和刷题是必不可少的。做知识梳理能加深你对原理的掌握程度,而刷题能提高你对技术面试的广度和深度。

附上我之前面试时收集的二十套一二线互联网公司Android面试真题(含BAT、小米、华为、美团、滴滴)和我自己整理Android复习笔记(包含Android基础知识点、Android扩展知识点、Android源码解析、设计模式汇总、Gradle知识点、常见算法题汇总共计732页)。

需要①二十套一二线互联网公司Android面试真题(含BAT、小米、华为、美团、滴滴)+②Android复习笔记(包含Android基础知识点、Android扩展知识点、Android源码解析、设计模式汇总、Gradle知识点、常见算法题汇总共计732页)的朋友————(此处免费打包领取)

腾讯Android面试真题(Java部分)

腾讯Android面试真题(Android部分)

一二线互联网公司Android面试真题分类总览

当程序员容易,当一个优秀的程序员真不容易,无论是面试还是进阶,每个阶段都需要靠不断的学习来提升自己,早早规划好自己的职业方向才能在工作和能力提升中甩开同龄人。————(此处免费打包领取)

上一篇 下一篇

猜你喜欢

热点阅读