Activity面试指南与面试题精选

文章目录


提起四大组件之首Activity,想必是无人不知无人不晓,不论多么初级的android工程师都会比较了解,接下来就总结下关于Activity的面试题。

1.生命周期

返回栈

Q:谈一下返回栈

首先理解android是使用Task来管理活动,一个Task就是一组存放在栈里的活动的集合,这个栈就叫做返回栈,每启动一个新的活动,就会将其放入栈顶,当我们点击back回退或调用activity的finish函数处于栈顶的活动就会出栈,前一个入栈的活动就会到栈顶,系统总是显示处于栈顶的活动。

活动生命周期

Q:说下Activity的生命周期?

在这里插入图片描述

  1. onCreate()方法:活动第一次创建的时候被调用,常做初始化的操作,比如加载布局(setContentView),绑定事件(findViewById)。表示Activity正在创建
  2. onStart()方法:活动由不可见到可见的时候被调用,表示Activity正在启动,此时Activity可见但不在前台
  3. onResume()方法:活动准备好和用户进行交互时调用。表示Acitivity获得焦点,此时Activity可见且在前台
  4. onPause()方法:系统准备去启动或恢复另一个活动时调用。表示Activity正在停止,此时可做存储数据,停止动画等操作。
  5. onStop()方法:在活动完全不可见的时候调用。表示Activity即将停止
  6. onDestory()方法:在活动被销毁之前调用,表示Activity即将销毁,常做回收工作、资源释放
  7. onRestart()方法:在活动由停止状态变为运行状态之前调用。表示Activity即将重启

Q:说下活动的生存期/(onStart方法/onStop()方法与onResume()方法/onPause()方法有什么区别)

活动的生存期分为三个:1.完整生存期 2.可见生存期 3.前台生存期
完整生存期:onCreate()方法与onDestory()都处于完整生存期,一般情况下,Activity会在onCreate()方法中完成各种初始化操作,而在onDestory()方法中完成释放内存的操作。
可见生存期:onStart()方法与onStop()方法就是可见生存期Activity对于用户是可见的,但无法与用户交互。onStart()方法中对资源进行加载,onStop()方法中对资源进行释放。
前台生存期:onResume方法与onPause方法就是前台生存期,在前台生存期内,活动处于运行状态,此时可以与用户交互。

Q:说下Activity处于onPasue()下可以执行那些操作?

1.用户返回该Activity,调用onResume()方法,重新running
2.用户打开了其他Activity,就会调用onStop()方法
3.系统内存不足,拥有更高权限的应用需要内存,该Activity就会被系统回收
4.如果用户返回到onStop()的Activity又显示在前台了,系统会调用

onRestart() -> onStart() -> onResume() 然后重新running

当Activity结束(调用finish()方法)就会调用onDestory()方法释放所有占用的资源。

生命周期的切换过程

1.启动一个Activity

onCreate->onStart->onResume

2.当一个Activity打开另一个Activity都会回调哪些方法,如果ActivityB是完全透明的呢,如果启动的是一个对话框Activity呢?

A:onPause->B:onCreate->B:onStart->B:onResume->A:onStop
如果ActivityB是完全透明的或对话框Activity则不会调用onStop。

3.启动新Activity后,又返回到旧的Activity

B:onPause->A:onRestart->A:onStart->A:onResume->B:onStop->B:onDestory

4.关闭屏幕/按Home键:

onPause->onStop

5.当一个Activity按Home键切换到桌面后又回到该Activity回调哪些方法。

onPause->onStop->onRestart->onStart->onResume

6.当一个Activity按back键回退时回调哪些方法

onPause->onStop->onDestory

Activity的优先级

1.可见且可以交互(前台Acitivity):正在和用户交互,优先级最高。
2.可见但不可以交互(可见但非前台Activity):比如当前Activity启动了一个对话框Activity,当前Activity就是可见但不可以交互。
3.后台Activity:已经被暂停的Activity,比如执行了onStop,优先级最低。
当系统内存不足,会按照优先级顺序从低到高去杀死目标Activity所在的进程。

Q:(1)优先级低的Activity在内存不足被回收后怎样做可以恢复到销毁前状态?/(2)横竖屏切换后怎样做可以恢复到销毁前状态?

回答:优先级低的Activity在内存不足被回收后重新打开(横竖屏切换的过程中)会引发Activity重建。
在Activity由于异常情况被终止时,系统会调用onSaveInstanceState方法来保存当前Activity的状态,该方法调用于onStop之前,与onPause方法没有时序关系。当异常终止的Activity被重建时,会调用onRestoreInstanceState方法(该方法在onStart之后),并且把Activity销毁时onSaveInstanceState保存的Bundle对象参数同时传递给onCreate方法onRestoreInstanceState方法。该方法的调用是在onStart之前。因此可通过onRestoreInstanceState(Bundle savedInstanceState)和onCreate((Bundle savedInstanceState)来判断Activity是否被重建,并取出数据进行恢复。但需要注意的是,在onCreate取出数据时一定要先判断savedInstanceState是否为空。
补充:其中onCreate和onRestoreInstanceState方法来恢复Activity的状态的区别
onRestoreInstanceState方法回调则说明bundle对象非空,不需要加非空判断,而onCreate需要非空判断。

Q:谈谈onSaveInstanceState() 与 onRestoreIntanceState()

onSaveInstanceState()

这两个方法并不是生命周期方法,它们并不一定会被触发。当应用遇到意外情况(如:内存不足、用户直接按Home键)由系统销毁一个Activity时,onSaveInstanceState() 会被调用,该方法的调用在onStop之前,与onPause没有时序关系但是当用户主动去销毁一个Activity时,例如在应用中按返回键,onSaveInstanceState()就不会被调用。因为在这种情况下,用户的行为决定了不需要保存Activity的状态。
onSaveInstanceState()时机:
(1)用户按下Home键
(2)横竖屏切换
(3)按下电源按钮(关闭屏幕显示)
(4)内存不足导致优先级的Activity被杀死

onRestoreIntanceState()

当被系统异常销毁的Activity被重建时,会调用onRestoreIntanceState或onCreate方法来恢复,而onRestoreInstance与Oncreate方法中传入的Bundle对象是销毁时onSaveInstanceState保存的,onRestoreIntanceState在onStart之后。

Q:onSaveInstanceState()与onPause()的区别?

onSaveInstanceState()只适合用于保存一些临时性的状态,而onPause()适合用于数据的持久化保存。

Q:谈谈横竖屏切换过程中调用的函数

要切记这里活动已经被销毁了。
onPause->onSaveInstanceState->onStop->onDestory()->onCreate->onStart->onRestoreIntanceState->onResume

Q:如何防止横竖屏切换(配置改变)时Activity销毁并切换

通过对AndroidManifest文件的Activity中指定(configChanges)属性:

android:configChanges = “orientation| screensize”

来避免横竖屏切换时,Activity的销毁和重建,而是回调了onCofigurationChanged()方法

@Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
    }

这里附上android configChanges的所有属性解释

“mcc“ 移动国家号码,由三位数字组成,每个国家都有自己独立的MCC,可以识别手机用户所属国家。
“mnc“ 移动网号,在一个国家或者地区中,用于区分手机用户的服务商。
“locale“ 所在地区发生变化。
“touchscreen“ 触摸屏已经改变。(这不应该常发生。)
“keyboard“ 键盘模式发生变化,例如:用户接入外部键盘输入。
“keyboardHidden“ 用户打开手机硬件键盘
“navigation“ 导航型发生了变化。(这不应该常发生。)
“orientation“ 设备旋转,横向显示和竖向显示模式切换。
“fontScale“ 全局字体大小缩放发生改变

生命周期的记忆方法

流程图

参考链接
这个onRestart其实应该画在onStart方法上面。
在这里插入图片描述
这里是想说明这些方法是两两对应的。onCreate创建与onDestory销毁,onStart方法Activity可见与onStop方法Activity不可见,而onResume方法获得焦点(在前台)与onPause方法取消焦点(不在前台)。而onRestart方法是在onStop后再次启动Activity时调用,下一步会直接调用onStart方法如果之前Activity调用了onDestory(被销毁)之后再次启动就会调用onCreate

切换过程的比喻

把Activity比作书本。书本现在都放置在书架上,我们想要阅读一本书(启动Activity),首先先将书从书架上拿下来(onCreate),然后放在桌子上准备读(onStart),之后我们打开书本开始读并做一些笔记(onResume)。

这个时候如果我们想要阅读另一本书,就要先合上书1(书1:onPause),然后从书架拿另一本书(书2:onCreate),然后放在桌子上并打开(书2:onStart,onResume)。
如果书1被完全盖住(就调用书1:onStop),如果没有被完全盖住就不调用onStop(比如书2是透明的,或书2是弹窗型Activity)。

我们也可以将书1返回书架(onDestory)。

2.Activity启动模式

1.android提供了四种Activity启动模式:
标准模式(standard)
栈顶复用模式(singleTop)
栈内复用模式(singleTask)
单例模式(singleInstance)
2. activity的管理是采用任务栈的形式,上文中已经提过。
在这里插入图片描述

1.Standard模式(标准模式)

标准模式就是我们最常用的模式,在该模式下,每当启动一个新的活动,它就会在返回栈中入栈,并处于栈顶的位置。该模式不会考虑活动是否已经存在栈中,每次启动都会创建该活动的一个新的实例

下面来看第一行代码中的例子。
在这里插入图片描述
运行程序,然后在FirstActivity中连续点击两次按钮,观察logcat中打印信息。
在这里插入图片描述
可以看到,每点击一次按钮就会创建一次FirstActivity的实例,此时返回栈中也会存在3个FirstActivity的实例,因此你需要连按3次Back键才能退出程序。

2.singleTop(栈顶复用模式)

如果需要新创建的Activity处于栈顶的话,那么Activity的实例就不会重建,而是重用栈顶的实例,并回调如下方法:

   @Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
    }

流程如下,当栈顶为ActivityA,而我们又一次要启动ActivityA,任务栈就不会继续增加ActivityA的实例,直接重用栈顶的实例。
在这里插入图片描述
如果栈顶不是新建的Activity,就会创建Activity新的实例,并放入栈顶。这里有个问题就是说比如我们重新调用的Activity处于任务栈中,但不位于栈顶的话,还是会创建实例。

下面来看第一行代码中的例子
我们让FirstActivity中的button1通过点击可以跳转到SecondActivity。
在这里插入图片描述
我们让SecondActivity的button2通过点击可以跳转到FirstActivity。
在这里插入图片描述
之后运行程序,在FirstActivity界面点击按钮进入到SecondActivity,然后在SecondActivity界面点击按钮,又会重新进入到FirstActivity。
在这里插入图片描述
当前Activity为SecondActivity时,任务栈task为【SecondActivity,FirstActivity】,此时点击button,跳转到FirstActivity,栈顶并非为FirstActivity,于是又会创建FirstActivity,并压入任务栈中,任务栈task为【FirstActivity,SecondActivity,FirstActivity】。

应用场景

1.在通知栏点击收到的通知,然后需要启动一个Activity,这个Activity就可以用singleTop,否则每次点击都会新建一个Activity。
2.防止快速多次点击Activity,多次启动。

3.singleTask模式(栈内复用模式)

与栈顶复用模式相对的,就是栈内复用模式,即一个栈内只有一个Activity的实例。可以在AndroidMainfest文件的Activity中指定该Activity需要加载到哪个栈中,即singleTask的Activity可以指定想要加载的目标栈。singleTask和taskAffinity配合使用,指定开启的Activity加入到哪个栈中。

<activity android:name=".Activity1"
	android:launchMode="singleTask"
	android:taskAffinity="com.lvr.task"
	android:label="@string/app_name">
</activity>

关于taskAffinity的值: 每个Activity都有taskAffinity属性,这个属性指出了它希望进入的Task。如果一个Activity没有显式的指明该Activity的taskAffinity,那么它的这个属性就等于Application指明的taskAffinity,如果Application也没有指明,那么该taskAffinity的值就等于包名。

下面来看第一行代码的实例。
继续使用singleTop中的FirstActivity和SecondActivity,并将FirstActivity的启动模式更改为SingleTask模式。
在这里插入图片描述
之后在FirstActivity中添加onRestart()方法,并打印日志。
在这里插入图片描述
最后在SecondActivity中添加onDestory()方法,并打印日志。
在这里插入图片描述
重新运行程序,在FirstActivity界面点击按钮进入到SecondActivity,然后在SecondActivity界面点击按钮,又会重新进入到FirstActivity。
在这里插入图片描述
可以看到在SecondActivity中启动FirstActivity时,会发现栈中已经有了FirstActivity的实例,并且在SecondActivity的下面,于是会让SecondActivity出栈,而FirstActivity又重新变成栈顶的Actiivity,因此会调用FirstActivity的onRestart方法与SecondActivity的onDestory方法,此时任务栈中只有FirstActivity。下图很好的说明了这个过程。
在这里插入图片描述
其实刚才说的这种情况前提在于FirstAcitivity指定要加载的栈(taskAffinity)为默认的栈。
因此该种启动模式有三种情况:
1.以singleTask启动ActivityD,同时其所需任务栈(taskAffinity)s1。当前情况下,存在s1栈,但s1栈中没有ActivityD,直接task1中压入ActivityD。
在这里插入图片描述
2.当前情况与第一行代码中情况类似。当前情况下,s1栈中存在ActivityB,因此需要将处于ActivityB上面的Activity全部出栈。
在这里插入图片描述
3.该情况为一种特殊情况,我们打算以singleTask启动ActivityD,比较栈为s2。而当前存在的栈为s1,没有s2任务栈,因此就直接创建一个新的栈,并将Activity压入。
在这里插入图片描述
总结:以SingleTask方式启动Activity时,会与指定的栈(如果没有指定就是默认栈)进行比较,如果该栈中存在该Activity就把栈中该Activity之上的Activity全部出栈,如果该栈中不存在该Activity就直接将该Acitivity压入栈中。

应用场景

应用于首页或登录页,用户在点击后退键可直接退出应用。
多数App的主页。对于大部分应用,当我们在主界面点击回退按钮的时候都是退出应用,那么当我们第一次进入主界面之后,主界面位于栈底,以后不管我们打开了多少个Activity,只要我们再次回到主界面,都应该使用将主界面Activity上所有的Activity移除的方式来让主界面Activity处于栈顶,而不是往栈顶新加一个主界面Activity的实例,通过这种方式能够保证退出应用时所有的Activity都能被销毁。

4.singleInstance(单例模式)

一看singleInstance其实就能想到是单例,以该模式启动Activity,就会直接创建一个新的任务栈,并创建该Activity的实例放入新栈中,一旦该模式的Activity实例已经存在于某个栈中,任何应用激活该Activity时都会重用该栈中的实例。
在这里插入图片描述

应用场景

呼叫来电界面。

面试题汇总

Q: 说下Activity的四种启动模式?

1.standard模式(标准模式):普通启动模式,每次启动Activity时,就会创建一个实例。
2.singletop模式(栈顶模式):当启动Activity时,会判断任务栈的栈顶是否为该Activity,如果是该Activity则不会创建实例,去**回调onNewIntent(intent)方法,否则会创建实例
3.singletask模式(栈内模式):当启动Activity时,只要该Activity在指定的栈中,就不会创建实例,去回调
onNewIntent(intent)**方法。如果不存在,会判断是否指定的栈不存在,就创建一个栈并将Activity的实例压入,如果指定的栈存在,就直接压入该栈中。
4.singleInstance模式(单实例模式):该模式下,创建Activity实例时,直接创建一个栈,栈中只有该Activity实例。之后无论哪个应用程序启动该Activity,都只会调用栈中该实例。

Q:谈谈singleTop和singleTask的区别以及应用场景

singleTop模式的含义是(参考上面问题),singleTask模式的含义是(参考上面问题),因此二者的差别为:
singleTop模式:该模式下,任务栈中可能有多个相同Activity实例,因为它只是判断当前启动的Activity是否在栈顶。
该模式的Activity会默认进入启动它所属的任务栈,不涉及任务栈的转换。常用于防止快速连续点击而创建多个Activity实例。
singleTask模式:该模式向,任务栈中只会有一个Activity实例,因为它会判断当前启动的Activity是否在当前指定的栈中。该模式下Activity可以通过taskAffinity去指定需要的任务栈,可能涉及任务栈的转换,常用于首页或登录页。因为不论我们在进入首页后进入了多少个Activity,当我们返回首页后,还是希望退出首页直接可以退出应用。该模式下会把栈中位于要启动的Activity上面的Activity都出栈。

Q:onNewIntent()调用时机?

有两个调用时机,分别是singleTop模式下与singleTask模式下启动Activity。
singleTop模式:当启动的Activity是在任务栈的栈顶时,会回调onNewIntent方法。
singleTask模式:当启动的Activity存在于任务栈中,会回调onNewIntent方法。

Q:了解哪些Activity启动模式的标记位?

  • FLAG_ACTIVITY_SINGLE_TOP:对应singleTop启动模式
  • FLAG_ACTIVITY_NEW_TASK:对应singleTask模式

Intent启动与匹配

1.显式启动与隐式启动

  • 显式启动

构建一个Intent对象,并传入FirstActivity.this作为上下文,并传入SecondActivity.class作为目标活动
在这里插入图片描述

  • 隐式启动
    首先在我们需要跳转的Activity中配置一个< intent-filter>
    在这里插入图片描述
    其中包括< action>标签与< category>标签,action标签代表当前活动可以响应当前action,而category标签则包含了一些附加信息。只有当Activity中的 < action>标签与< category>标签同时匹配intent中的< action>标签与< category>标签,这个Activity才可以响应Intent,也就是说可以跳转至当前Activity
    下面的代码是FirstActivity中的部分代码,通过点击button1,可以跳转至SecondActivity。
    在这里插入图片描述
    每个intent只能有一个action,但可以有多个category,假如我们做了如下操作,就无法跳转,因为没有Activity可以响应当前的intent。
    在这里插入图片描述
隐式启动的例子

其实隐式启动有个最直接的例子,就是打开APP后首先显示的Activity就是隐式启动。因为我们为首先打开的Activiity设置了其intent-filter标签,标签中action为android.intent.action.MAIN,category为android.intent.category.LAUNCHER

 <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

另一个例子就是BroadCast的工作机制,不论是静态注册BroadCastReceiver,还是动态注册,都要写IntentFilter标签的,其中包含想要接收广播的action。

自定义广播的发送是通过intent来完成的,创建intent,添加action后,使用sendBroadcast发送广播。

 Intent intent = new Intent();
 intent.setAction("com.example.aaa.special");
 sendBroadcast(intent);

静态注册就是在AndroidManifest中给Receiver写一个IntentFilter标签,并写入想要接收广播的action。

<receiver
 	android:name=".AnotherReciver"
 	android:enabled="true"
 	android:exported="true">
 	<intent-filter>
		<action android:name="com.example.aaa.special"></action>
	</intent-filter>
</receiver>

而动态注册需要在Activity中创建Recevier的实例,创建一个IntentFilter实例,并通过addAction添加action。最后使用registerReceiver方法传入Recevier实例与IntentFilter实例。

private IntentFilter intentFilter;
private NetworkChangeReceiver networkChangeReceiver;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        intentFilter = new IntentFilter();
        intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");
        networkChangeReceiver = new NetworkChangeReceiver();
        registerReceiver(networkChangeReceiver,intentFilter);
        }   
	@Override
    protected void onDestroy(){
        super.onDestroy();
        unregisterReceiver(networkChangeReceiver);
    }

2.匹配原则

原则:
1.一个intent只有同时匹配某个Activity的intent-filter中的action、category、data才算完全匹配,才能启动
该Activity。
2.一个Activity可以有多个 intent-filter,一个 intent只要成功匹配任意一组 intent-filter,就可以启动
该Activity。
action匹配原则

1.要求intent中的action必须存在且和一组intent-filter中的action完全相等
2.区分大小写。

category匹配原则

1.intent可以没有category,因为会有默认的值。
2.否则intent中的category要求与那一组intent-filter中的全部category完全相同。

data匹配原则

1.如果intent-filter中有定义data,那么Intent中也必须也要定义date。
2.data主要由mimeType(媒体类型)和URI组成。在匹配时通过intent.setDataAndType(Uri data, String type)方法对data进行设置。

判断是否匹配

采用隐式方式启动Activity时,可以用PackageManagerresolveActivity方法或者IntentresolveActivity方法判断是否有Activity匹配该隐式Intent。

参考链接:

2019校招Android面试题解1.0(上篇)
Android BestNote
《第一行代码》

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章