- 启动模式
- standard模式是Activity默认的启动模式。每启动一个Activity就在栈顶创建一个新的实例。
- singleTop顾名思义,栈顶单例。如果有时候satndard模式并不合理,比如当前Activity已处于栈顶,再次启动此Activity会重新创建实例,不会直接复用。
- singleTask模式,顾名思义,任务栈中只有一个实例。启动某个Activity时,会先检查任务栈中是否有该Activity的实例,有就直接复用(把前面所有的Activity出栈),没有才创建并入栈。浏览器的主界面通常采用此模式。
- singleInstance模式会启动一个新的任务栈来管理当前程序中singleInstance模式启动的Activity,在Android系统中,该Activity只有一个实例。
这种模式主要是为了,在不同程序间共享同一个Activity实例。
- 生命周期
- Activity启动–>onCreate()–>onStart()–>onResume();
- 点击home键回到桌面–>onPause()–>onStop();
- 再次回到原Activity时–>onRestart()–>onStart()–>onResume();
- 退出当前Activity时–>onPause()–>onStop()–>onDestroy();
- 配置变化且没有在Manifest中声明时,横竖屏时,横屏一次,竖屏两次;
- 什么时候Activity单独走onPause()不走onStop()?
- 当前Activity的Theme为Theme.Dialog时,只走onPause。
- 什么时候Activity不执行onDestory()?
- 栈里面的第一个没有销毁的activity会执行ondestroy方法,其他的不会执行。比如说:从mainactivity跳转到activity-A(或者继续从activity-A再跳转到activity-B),这时候,从后台强杀,只会执行mainactivity的onDestroy方法,activity-A(以及activity-B)的onDestroy方法都不会执行;
- onSaveInstanceState()被执行的场景有哪些:
- 当用户按下HOME键时
- 长按HOME键,选择运行其他的程序时
- 锁屏时
- 从activity A中启动一个新的activity时
- 屏幕方向切换时
- Activity启动流程:
a. Activity1调用startActivity,实际会调用Instrumentation类的execStartActivity方法,Instrumentation是系统用来监控Activity运行的一个类,Activity的整个生命周期都有它的影子;
b. 通过跨进程的binder调用,进入到ActivityManagerService中,其内部会处理Activity栈,通知Activity1 Pause,Activity1 执行Pause 后告知AMS;
c. 在ActivityManagerService中的startProcessLocked中调用了Process.start()方法。并通过连接调用Zygote的native方法forkAndSpecialize,执行fork任务。之后再通过跨进程调用进入到Activity2所在的进程中;
d. ApplicationThread是一个binder对象,其运行在binder线程池中,内部包含一个H类,该类继承于类Handler。主线程发起bind Application,AMS 会做一些配置工作,然后让主线程 bind ApplicationThread,ApplicationThread将启动Activity2的信息通过H对象发送给主线程。发送的消息是EXECUTE_TRANSACTION,消息体是一个 ClientTransaction,即 LaunchActivityItem。主线程拿到Activity2的信息后,调用Instrumentation类的newActivity方法,其内通过ClassLoader创建Activity2实例;
e. 通知Activity2去performCreate,走生命周期流程。 - a->b->c界面,其中b是SingleInstance的,那么c界面点back返回a界面,为什么?
- singleInstance模式是存在于另一个任务栈中的。也就是说ActivityA和ActivityC是处于同一个任务栈中的,ActivityB则是存在另个栈中。所以当关闭了ActivityC的时候,它自然就会去找当前任务栈存在的activityA。当前的activity都关闭了之后,才会去找另一个任务栈中的activity。也就是说当在ActivityC中finish之后,会回到ActivityA的界面,在ActivityA里finish之后会回到ActivityB界面。
- Activity常用的标记位Flags
-
FLAG_ACTIVITY_NEW_TASK
此标记位作用是为Activity指定“singleTask”启动模式,其效果和在XML中指定相同android:launchMode="singleTask"
-
FLAG_ACTIVITY_SINGLE_TOP
此标记位作用是为Activity指定“singleTop”启动模式,其效果和在XML中指定相同android:launchMode="singleTop"
-
FLAG_ACTIVITY_CLEAR_TOP
具有此标记位的Activity,当它启动时,在同一个任务栈中位于它上面的Activity都要出栈。此标记位一般会和singleTask启动模式一起出现,此情况下,若被启动的Activity实例存在,则系统会调用它的onNewIntent。
-
FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
具有此标记位的Activity不会出现在历史Activity的列表中,当某些情况我们不希望用户通过历史列表回到我们的Activity时这个标记比较有用。他等同于在XML中指定Activity的excludeFromRecents属性。android:excludeFromRecents="true"
- 你知道onNewIntent吗?
- 如果IntentActivity处于任务栈的顶端,也就是说之前打开过的Activity,现在处于onPause、onStop 状态的话,其他应用再发送Intent的话,执行顺序为:onNewIntent,onRestart,onStart,onResume。
- 有什么方法可以启动一个没有在AndroidManifest.xml中注册过的Activity?
- 通过Hook AMS,插件化技术原理,用一个已经注册过的Activity去欺骗AMS和PMS的检查,然后真正创建Ativity和启动的时机替换成真的Activity。(没试过)
- Intent传递数据是否有限制?
- intent传递数据有限制,实质上是由Binder内核传递,并不是为了传输大量数据而设计,而是为了进程间频繁通信所设计,内核限制是4M,在APP中限制了不到1M(比1M略小的值),真机中可能还有其他任务在占用,最好在512k以内。否则会报错TransactionTooLargeException。
- 如何在Application中获取当前Activity实例
- 在Application类,通过实现Application.ActivityLifecycleCallbacks接口调用registerActivityLifecycleCallbacks,在onActivityResumed(Activity activity) 方法中记录当前显示的Activity,注意内存泄漏。