Activity的生命周期及常见回调顺序
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Activity的生命周期及常见回调顺序相关的知识,希望对你有一定的参考价值。
参考技术A关于Activity的生命周期相信不少人都觉得自己很了解了,毕竟大多数入门的时候都会首先学这个,但事实真的是这样吗?当初我也是这样想,直到在面试的时候栽了跟头~ 在哪跌倒就在哪爬起来,本文带你全面的了解一下Activity的生命周期,面试再问到也不怕啦
首先按照官方生命周期流程图逐个解释生命周期回调
当Activity首次创建的时候触发,这是生命周期的第一个方法,我们需要重写这个回调,并在调用setContentView()去加载界面布局资源,以及实例化一些变量。该方法有一个参数savedInstanceState,该参数包含Activity先前保存状态的Bundle对象。如果Activity是由于异常情况(切换横竖屏,内存不足等)被杀掉的,则Bundle对象的值不为null,否则Bundle的值为null。所以如果想要在onCreate()中做恢复工作需要对Bundle判断是否为空。不过建议在onRestoreInstanceState()方法中做恢复工作,因为该方法一旦被调用则Bundle不会为空。
表示Activity正在重新启动。一般情况下,当当前Activity从不可见重新变为可见状态时,onRestart就会被调用。这种情形一般是用户行为导致的,比如用户按Home键切换到桌面或打开了另一个新的Activity,接着用户又回到了这个Actvity。
表示Activity正在被启动,即将开始,这时Activity已经出现了,但是还没有出现在前台,无法与用户交互。这个时候可以理解为Activity已经显示出来,但是我们还看不到。
相信很多人会有疑问,什么叫Activity已经显示出来了,但是看不到???因为我们能看到的都是View或者和View有关联的东西,而Activity确实是没有什么直观的东西让我们看到的。所以这里说的看不到其实是看不到View,因为此时View还不是可见的,只有在onResume的时候才会把View设置为可见,想了解清楚的可以查看 Window和WindowManager的创建与Activity
此时Activity进入前台,具备与用户交互的能力。与onStart()都是对用户可见,但是onStart()时Activity是位于后台的,onResume()时Activity才显示到前台。 如果我们在onPause()中释放了组件,我们应该在onResume()中重新初始化。 我们应该在这里开始动画和初始化一些只有用户关注时才使用的组件。
当用户离开了Activity时会回调这个方法,比如说:
我们可以在这个方法中执行一些释放资源的操作,比如broadcast receivers,sensors,以及一些用户在不交互时不需要的资源。
该方法执行的时间非常简短,因此不应该在这个方法保存程序或用户数据;在该方法完成之前,保存工作可能并未完成。而且会影响到新的Activity的显示,因为onPause()执行完,新Activity才会开始执行onCreate()。
当Activity对用户不再可见的时候会回调该方法,比如说启动一个新的Activity把屏幕全都遮住了。
之前说过不建议在onPause()做一些重量级的释放工作,应该交由onStop()去释放大多数资源。比如unregisterReceiver(),还有其他可能导致内存泄露的资源,因为系统可能在没有回调onDestroy()的时候就杀掉了进程。
在Activity被销毁之前会回调该方法,这也是Activity生命周期的最后一个回调。
如果在Activity调用了finish()或者由于内存紧张系统销毁了该Activity,也有可能是由于横竖屏的切换或者用户按了返回键都会导致该方法的回调,
我们应该在这个方法中回收之前没有回收掉的所有资源
ActivityA:onPause() ->ActivityB:onCreate()->ActivityB:onStart()->ActivityB:onResume()-> ActivityA:onStop()
当ActivityA调用完onPause()之后才会调用ActivityB的onCreate(),所以不要在onPause()中做耗时操作,会影响新Activity的显示。
只有当ActivityB的onResume()调用完之后才会调用ActivityA的onStop(),因为此时ActivityB在最上面,ActivityA才是完全不可见的。
onPause()->onSaveInstanceState()->onStop()->onDestroy()->onCreate()->onStart()->onRestoreInstanceState()->onResume()
如果没有在androidManifest设置configChanges,则屏幕旋转的时候会吧Activity销毁再重建,并且重建后的Activity和原来的不是同一个实例。
如果设置了android:configChanges="orientation|screenSize",则屏幕旋转时只会调用onConfigurationChanged()方法,并且不会销毁重建
首先每个应用最少有一个进程,我们的Activity都是运行在进程中的,当应用退到后台时,系统可能因为内存不足而杀掉优先级低的进程,那么再该进程中的Activity都会被杀死,这种情况是不会走Activity的生命周期的,只有杀掉单个Activity的时候才会走Activity的onDestroy()方法。
onPause()->onStop()->onDestroy()
当Activity弹出Dialog获取PopupWindow是不会走任何生命周期的。
弹出DialogActivity原来的Activity会执行onPause(),关闭DialogActivity原来的Activity执行onResume()
onPause()->onStop()->onRestart()->onStart()->onResume()
onPause()->onNewIntent()->onResume()
Activity常见问题
Activity常见问题
通过这篇博客,我们能知道以下问题:
Activity
各种情况下的生命周期- 弹出
Dialog
对Activity
生命周期有什么影响? onActivityResult()
在哪两个生命周期之间回调?Activity
在onResume()
之后才显示的原因是什么?- 通过 Sheme 协议打开
Activity
Activity
什么时候会发生重建?- 在
Activity
的onCreate()
方法里写死循环会 ANR 吗?
1. Activity 生命周期方法相关
生命周期的回调方法
Activity生命周期的回调主要有 onCreate()
、onRestart()
、onStart()
、onResume()
、onPause()
、onStop()
、onDestory()
几个方法。
调用时机说明:
onCreate()
:系统创建Activity
时触发,用来初始化 Activity 的基本组件。onRestart()
:当处于“已停止”状态的Activity
即将重启时,系统就会调用此回调。onStart()
:Activity
将进入“已启动”状态,并对用户可见。onResume()
:系统会在Activity
开始与用户互动之前调用此回调。此时,该Activity
位于Activity
堆栈的顶部,并会捕获所有用户输入onPause()
:当Activity
失去焦点并进入“已暂停”状态时,系统就会调用此回调。onStop()
:当Activity
对用户不再可见时,系统就会调用此回调。onDestory()
:系统会在销毁Activity
之前调用此回调。此回调是Activity
接收的最后一个回调。通常,实现onDestroy()
是为了确保该Activity
的所有资源。
onStart()
和 onStop()
是从 Activity
是否可见来回调的,onResume()
和 onPause()
是从 Activity
是否位于前台来回调的。
在生命周期里几种状态:
-
Activity
的整个生命周期发生在onCreate()
与onDestroy()
之间,在onCreate()
中执行“全局”状态设置(例如状态布局),并在onDestroy()
中释放资源。 -
Activity
的可见生命周期发生在onStart()
与onStop()
之间,在这段时间内Activity
对用户可见。在整个生命周期中,当 Activity 在对用户可见和隐藏俩种状态中交替变化时,系统会多次调用onStart()
和onStop()
。 -
Activity
的前台生命周期发生在onResume()
与onPause()
之间,Activity
位于其他Activity
之前(栈顶位置),可与用户交互并具有输入焦点。但状态改变频繁,系统会多次调用onResume()
和onPause()
,建议做些轻量级操作。
打开Activity时两个Activity的生命周期方法的回调顺序
当一个 Activity
启动另一个 Activity
时,它们都会经历生命周期转换。第一个 Activity
停止运行并进入“已暂停”或“已停止”状态,同时创建另一个 Activity
。
-
Activity
A 启动Activity
B,BActivity
的launchMode
为standard
或者 BActivity
没有可复用的实例时: A.onPause()
-> B.onCreate()
-> B.onStart()
-> B.onResume()
-> A.onStop()
--> A.onDestory()
(如果需要关闭Activity A[A 被移出栈]) -
Activity
A 启动Activity
B,BActivity
的launchMode
为singleTop
且 BActivity
已经在栈顶时(一些特殊情况如通知栏点击、连点、BActivity
自己打开自己),此时只有 B 页面自己有生命周期变化:B.onPause()
-> B.onNewIntent()
-> B.onResume()
-
当 B
Activity
的launchMode
为singleInstance
,singleTask
且对应的 BActivity
有可复用的实例时:A.onPause()
-> B.onNewIntent()
-> B.onRestart()
-> B.onStart()
-> B.onResume()
-> A.onStop()
--> A.onDestory()
(如果需要关闭Activity A[A 被移出栈]) -
当 B
Activity
的Theme
为Dialog
时:A.onPause()
-> B.onCreate()
-> B.onStart()
-> B.onResume()
(注意前一个Activity
不会回调onStop()
,因为只有在Activity
切到后台(不在Activity栈顶)不可见才会回调onStop()
;而弹出Dialog
主题的Activity
时前一个页面还是可见的,只是失去了焦点而已所以仅有onPause()
回调)
2. 弹出 Dialog
对 Activity
生命周期有什么影响?
**先下结论:**通过 《Android Activity——启动过程探索(一)》 《Android Activity——启动过程探索(二)》 《Android Activity——启动过程探索(三)》 我们知道Activity
生命周期回调都是通过ActivityTaskManagerService
(ATMS)(在Android 10之前是通过 ActivityManagerService
(AMS))来回调的。但是弹出 Dialog
、Toast
、PopupWindow
本质上都直接是通过 WindowManager.addView()
显示的(没有经过 ATMS/AMS),所以不会对生命周期有任何影响。
Dialog显示过程源码解析
源码版本为 Android 10(Api 29),不同Android版本可能有一些差别
-
构造方法中获取
WindowManager
和创建PhoneWindow
并通过PhoneWindow
的setWindowManager()
方法关联public Dialog(@NonNull Context context, @StyleRes int themeResId) this(context, themeResId, true); Dialog(@NonNull Context context, @StyleRes int themeResId, boolean createContextThemeWrapper) // 获取 WindManager,实际为实现类 WindowManagerImpl mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); // 创建 PhoneWindow 对象 final Window w = new PhoneWindow(mContext); mWindow = w; w.setCallback(this); w.setOnWindowDismissedCallback(this); w.setOnWindowSwipeDismissedCallback(() -> if (mCancelable) cancel(); ); w.setWindowManager(mWindowManager, null, null); w.setGravity(Gravity.CENTER); mListenersHandler = new ListenersHandler(this);
-
Dialog#show()
方法源码实现public void show() mCanceled = false; if (!mCreated) dispatchOnCreate(null); // 没有创建过的话,调用 onCreate() 方法 else // 创建过的话,就不在调用 onCreate() 回调,只是修改配置 final Configuration config = mContext.getResources().getConfiguration(); mWindow.getDecorView().dispatchConfigurationChanged(config); onStart(); // 调用 onStart() 回调方法 mDecor = mWindow.getDecorView(); // 通过 PhoneWindow 获取 DecorView ... // 省略,设置默认logo、icon以及确定软键盘模式等 // 通过 WindowManager(实际为WindowManagerImpl对象)将DecorView增加窗体上 mWindowManager.addView(mDecor, l); ... // 设置软键盘模式 mShowing = true; // 修改显示标记为 true sendShowMessage(); // WindowManagerImpl 的 addView() 方法 @Override public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) applyDefaultToken(params); // 调用 WindowManagerGlobal 的 addView() 方法 mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow); // WindowManagerGlobal 的 addView() 方法核心代码 public void addView(View view, ViewGroup.LayoutParams params, Display display, Window parentWindow) ViewRootImpl root; View panelParentView = null; synchronized (mLock) // 创建 ViewRootImpl 对象 root = new ViewRootImpl(view.getContext(), display); view.setLayoutParams(wparams); // 调用 ViewRootImpl 的 setView() 方法 root.setView(view, wparams, panelParentView); // ViewRootImpl 的 setView() 方法核心代码 public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) synchronized (this) if (mView == null) mView = view; // 调用 requestLayout() 方法,进行布局(包括measue、layout、draw) requestLayout(); mOrigWindowType = mWindowAttributes.type; mAttachInfo.mRecomputeGlobalAttributes = true; collectViewAttributes(); // 通过调用 Session 的 addToDisplay() 方法 res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes, getHostVisibility(), mDisplay.getDisplayId(), mTmpFrame, mAttachInfo.mContentInsets, mAttachInfo.mStableInsets, mAttachInfo.mOutsets, mAttachInfo.mDisplayCutout, mInputChannel, mTempInsets); setFrame(mTmpFrame);
ViewRootImpl
的 setView()
方法说明:
-
mWindowSession
是通过WindowManagerGlobal
的getWindowSession()
方法获取到的,返回的是通过WindowManagerService
的openSession()
方法创建的Session
对象 -
mWindow 对象为
ViewRootImpl
的 内部类static class W extends IWindow.Stub
,通过定义可以看出来,是一个Binder
对象 -
Session
对象的addToDisplay()
方法Override public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs, int viewVisibility, int displayId, Rect outFrame, Rect outContentInsets, Rect outStableInsets, Rect outOutsets, DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel, InsetsState outInsetsState) // mService 为 WindowManagerService,window 就是上面的 `ViewRootImpl` 的 内部类 `static class W extends IWindow.Stub` return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId, outFrame, outContentInsets, outStableInsets, outOutsets, outDisplayCutout, outInputChannel, outInsetsState);
通过这个方法就能够实现客户端与 WindowManagerService
的双向调用了(应用端通过 mWindowSession 调用 WMS, WMS 通过 mWindow (一个 Binder 对象) 调用应用端)
DialogFragment源码解析
注意:该部分源码来自 support v4 包
看 DialogFragment
的定义
class DialogFragment extends Fragment
发现就是直接继承了 Fragment
,那么就可以肯定,Fragment
有的 DialogFragment
都有,像生命周期方法等,又因为我们可以通过 getDialog()
方法获取到 Dialog
。所以可以肯定它包含一个了 Dialog
。接着我们先看 show()
方法
public void show(FragmentManager manager, String tag)
mDismissed = false;
mShownByMe = true;
FragmentTransaction ft = manager.beginTransaction();
ft.add(this, tag);
ft.commit();
发现就是将 DialogFragment
显示出来,那我们接着找一下,看看 Dialog
是在哪里创建的。发现如下代码:
@Override
public LayoutInflater getLayoutInflater(Bundle savedInstanceState)
mDialog = onCreateDialog(savedInstanceState);
return (LayoutInflater) mActivity.getSystemService(
Context.LAYOUT_INFLATER_SERVICE);
@NonNull
public Dialog onCreateDialog(Bundle savedInstanceState)
return new Dialog(getActivity(), getTheme());
发现是在 getLayoutInflater()
方法中创建的,那么这个 getLayoutInflater()
方法又是在哪里被调用的呢?通过查找我们发现这个方法是在 FragmentManager
中调用的,调用完这个方法之后就会调用 Fragment
的 onViewCreated()
方法;而 方法的返回值 LayoutInflater
就是 Fragment
中回调方法 onCreateView()
的参数。
分析到这里,我们就知道了,DialogFragment
实际上是一个 Fragment
,只是他在 onViewCreated()
方法之前通过 getLayoutInflater()
方法创建了一个 Dialog
,也就是一个普通的 Fragment
中包含了一个 Dialog
。那么又出现了问题,我们刚刚看了 show()
方法,发现并没有调用 Dialog。show()
方法,那么 Dialog
是怎么显示的呢?我们前面就说过,DialogFragment
实际上是一个 Fragment
,Fragment
有的 DialogFragment
都有;我们都知道Fragment
有一个生命周期方法 onStart()
是在用户可见时被调用的,那么 Dialog.show()
方法是否在该方法种调用了,看一下代码:
@Override
public void onStart()
super.onStart();
if (mDialog != null)
mViewDestroyed = false;
mDialog.show();
果然,在 Fragment
的生命周期方法 onStart()
回调中,调用了 Dialog.show()
方法,那么当我么调用 DialogFragment
的 show()
方法时,把将 DialogFragment
显示出来了,那么 Fragment
的生命周期方法 onStart()
自然会被回调,Dialog
自然也就显示出来了。Fragment
的生命周期方法回调并非由 ActivityManagerService
(AMS)【Android 10 以上 ActivityTaskManagerService
(ATMS)】来控制,而是通过 FragmentManager
回掉的,也不会影响到 Activity
的生命周期。
3. onActivityResult 在哪两个生命周期之间回调?
onActivityResult 不属于 Activity 的生命周期。但是答案很简单,因为在 onActivityResult()
方法的注释中就写着答案:「You will receive this call immediately before onResume() when your activity is re-starting.」 所以 onActivityResult()
回调先于该 Activity
的所有生命周期回调,从 B Activity
返回 A Activity
的生命周期调用为:
B.onPause()
-> A.onActivityResult()
-> A.onRestart()
-> A.onStart()
-> A.onResume()
4. Activity 在 onResume 之后才显示的原因是什么?
通过《Android自定义View之Activity页面的组成》我们知道了在 Activity
中调用 setContentView()
方法会将我们的 View
添加到 DecorView
中,DecorView
也是一个控件,他要加载到界面上让用户可见,是通过 Window
(也就是 PhoneWindow
)来完成的,所以我们只要知道 PhoneWindow
是在什么时候将 DecorView
加载出来的,就知道了用户是在什么时候才可见布局信息。那么,到底是什么时候开始将 DecorView
添加到 PhoneWindow
中的了, 在 《Android Activity——启动过程探索(二)》 中,我们说到了 Activity
的回调 onResume()
方法,中间有一段是会调用 ActivityThread#handleResumeActivity()
方法,我们来看一下这个方法的源码(省略大部分代码之后的核心代码):
@Override
public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward, String reason)
// 回调 onResume() 方法
final ActivityClientRecord r = performResumeActivity(token, finalStateRequest, reason);
final Activity a = r.activity;
if (r.window == null && !a.mFinished && willBeVisible)
r.window = r.activity.getWindow(); // 获取PhoneWindow并赋值
View decor = r.window.getDecorView(); // 获取 DecorView 控件
decor.setVisibility(View.INVISIBLE);
// 获取ViewManager,也就是WindowManager(因为interface WindowManager extends ViewManager)
ViewManager wm = a.getWindowManager();
a.mWindowAdded = true;
wm.addView(decor, l); // 关键点
方法说明:
-
ViewManager wm = a.getWindowManager()
方法最终返回的是WindowManagerImpl
对象,原因如下:Activity.getWindowManager()
方法返回Activity
的成员变量mWindowManager
Activity
的成员变量mWindowManager
在Activity
的attach()
方法中被赋值mWindowManager = mWindow.getWindowManager()
,调用的是Window
的getWindowManager()
方法Window
的getWindowManager()
方法返回的是他的成员变量mWindowManager
Window
的成员变量mWindowManager
在他的setWindowManager()
方法中被赋值mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this)
,所以得出结论a.getWindowManager()
方法最终返回的是WindowManagerImpl
对象
-
关键点
wm.addView(decor, l)
调用的就是WindowManagerImpl#addView()
方法了,之后的调用过程在当前文章前面【Dialog#show()
方法源码实现】 部分已经说过了,就不在重复了。
通过以上分析,我们就知道了实际上 Activity
中的布局内容是在 onResume()
回调之后才挂载到 Window
上的,也就是这个时候才是对用户可见的。
5. 通过 URL Sheme 协议打开 Activity
URL Scheme 是一种页面内跳转协议,通过这个协议可以比较方便的跳转到app某一个页面,也可以通过 h5 打开App页面。
URL Sheme 的格式:[scheme]😕/[host][:port]/[path]?[query]
- scheme:协议名称 [scheme]😕/ 为必填,其他为非必填
- host:主机名(域名)
- port:端口号
- path:路径
- query:参数(多个参数之间用 & 分割,类似 get 请求)
使用
1. APP端需要能通过 sheme
打开的 Activity
进行配置 intent
过滤器(在清单文件中配置)
<activity android:name=".TestActivity">
<!--Android 接收外部跳转过滤器-->
<!--要想在别的App上能成功调起App,必须添加intent过滤器-->
<intent-filter>
<!-- 协议部分配置 ,注意需要跟web配置相同-->
<data
android:host="action.test.activity"
android:pathPrefix="/test"
android:port="999"
android:scheme="testapp" />
<!--下面这几行也必须得设置-->
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
</intent-filter>
</activity>
data属性说明:
-
scheme: 协议名称,必填,其他为非必填(由开发人员自定义)
-
host: 域名
-
port:端口
-
path: 完整的路径,如:http://example.com/blog/abc.html,这里将 path 设置为 /blog/abc.html 才能够进行匹配
-
pathPrefix:路径的开头部分,拿上来的 Uri 来说,这里将 pathPrefix 设置为 /blog 就能进行匹配了
-
pathPattern:用表达式来匹配整个路径,匹配符如下:
- “” 用来匹配0次或更多,如:“a” 可以匹配“a”、“aa”、“aaa”…
- “.” 用来匹配任意字符,如:“.” 可以匹配“a”、“b”,“c”…
- 因此 “.*” 就是用来匹配任意字符0次或更多
2. 在 Activity
获取 sheme
信息:
Uri uri = getIntent().getData();
if (uri != null)
// 完整的url信息
Log.i(TAG, "url:" + uri);
// scheme部分
String scheme = uri.getScheme();
Log.i(TAG, "scheme:" + scheme);
// host部分
String host = uri.getHost();
Log.i(TAG, "host:" + host);
// port部分
int port = uri.getPort();
Log.i(TAG, "port:" + port);
// 访问路劲
String path = uri.getPath();
Log.i(TAG, "path:" + path);
List<String> pathSegments = uri.getPathSegments();
Log.i(TAG, "pathSegments:" + pathSegments);
// Query部分
String query = uri.getQuery();
Log.i(TAG, "query:" + query);
//获取指定参数值
String params1 = uri.getQueryParameter("params1");
String params2 = uri.getQueryParameter("params2");
Log.i(TAG, "params1:" + params1 + " params2:" + params2);
3. 打开 Activity
的方式
1. 通过原生代码打开
String uri = "testapp://action.test.activity:999/test?params1=1¶ms2=true";
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(uri));
startActivity(intent);
1. 通过h5代码打开(使用浏览器打开包含如下代码的 html 文件)
<html>
<title>测试</title>
<body>
<a href="testapp://action.test.activity:999/test?params1=1¶ms2=true">打开APP</a>
</body>
</html>
6. Activity 什么时候会发生重建?
发生时机:
- 系统资源回收:内存不足,低优先级的Activity会被杀死
- 配置发生变化:当系统配置发生变化时,比如屏幕方向、语言的改变
横竖屏切换不销毁重建的方式
在清单文件中为该 Activity
配置 android:configChanges
属性。属性值 orientation|screenSize
(Api级别为13以下时只需要配置 orientation
即可) 对应着旋转屏幕,locale
对应着语言变化。如此,在配置发生变化时,不会导致重建,而是走 onConfigurationChanged()
回调方法。
保存和恢复住状态
保存和恢复状态分别通过 onSaveInstanceState()
方法和 onRestoreInstanceState()
方法实现。
Activity
的onSaveInstanceState()
执行在onStop()
之前,与onPause()
没有固定的时序关系;onRestoreInstanceState()
执行在onStart()
之后。不止Activity
有这两个方法,每个View
也有这两个方法,用来保存View
的信息。- 正常情况下的活动销毁并不会调用这两个方法,只有当活动异常销毁并且有机会重现展示的时候才会进行调用。
- 在
Activity
中onRestoreInstanceState()
和onCreate()
都可以进行数据恢复工作,但建议采用在onRestoreInstanceState()
中去恢复(因为调用了这个方法,用来存取数据的Bundle
肯定不为null
)。 - 在
onSaveInstanceState()
和onRestoreInstanceState()
这两个方法中,系统会默认为我们进行一定的恢复工作,比如:会为布局中的每个View
调用相应的onSaveInstanceState()
方法,让每个视图都能提供有关自身的应保存信息。
具体调用时机说明
Activity#onSaveInstanceState()
方法调用时机:
- 当用户按下HOME键时
- 从最近应用中选择运行其他的程序时
- 按下电源按键(关闭屏幕显示)时
- 从当前activity启动一个新的activity时
- 屏幕方向切换时(无论竖屏切横屏还是横屏切竖屏都会调用)
- 被系统回收时
Activity#onRestoreInstanceState()
方法调用时机:
- 被系统回收且重建时
- 屏幕方向切换时(无论竖屏切横屏还是横屏切竖屏都会调用)
- 语言切换时
7. 在 Activity 的 onCreate()
方法里写死循环会 ANR 吗?
ANR全称:Application Not Responding,也就是应用程序无响应
Android 中产生 ANR 的原因:
- Service TimeOut: service 未在规定时间执行完成:前台服务 20s,后台 200s
- BroadCastQueue TimeOut: 未在规定时间内未处理完广播:前台广播 10s 内, 后台 60s 内
- ContentProvider TimeOut: publish 在 10s 内没有完成
- Input Dispatching timeout: 5s 内未响应键盘输入、触摸屏幕等事件
根据以上 ANR 产生的原因,说明在 Activity
的 onCreate()
方法中写死循环是不会发生ANR的,但是主线程被死循环一直占用了,所以当再有其他事件产生时,就不能及时响应了,从而导致ANR发生。
以上是关于Activity的生命周期及常见回调顺序的主要内容,如果未能解决你的问题,请参考以下文章
Android——Activity和Intent及Activity的生命周期
关于android应用activity生命周期中,按下home键和按下back键的问题