-
关于生命周期
1、三个不常用生命周期:onContentChanged、onPostCreate、onPostResume
七大常用基本生命周期已经是老生常谈的了,就不再赘述。这里说三个不常用的方法:
onContentChanged:在Activity的setContentView()或addContentView()方法执行完毕时就会调用该方法。可以看下源码:
class AppCompatDelegateImplV7 extends AppCompatDelegateImplBase
implements MenuBuilder.Callback, LayoutInflaterFactory {
.
.
.
@Override
public void setContentView(View v, ViewGroup.LayoutParams lp) {
ensureSubDecor();
ViewGroup contentParent = (ViewGroup) mSubDecor.findViewById(android.R.id.content);
contentParent.removeAllViews();
contentParent.addView(v, lp);
mOriginalWindowCallback.onContentChanged();
}
@Override
public void addContentView(View v, ViewGroup.LayoutParams lp) {
ensureSubDecor();
ViewGroup contentParent = (ViewGroup) mSubDecor.findViewById(android.R.id.content);
contentParent.addView(v, lp);
mOriginalWindowCallback.onContentChanged();
}
可以看到,在setContentView()和addContentView()方法最后都调用了onContentChanged()方法。
onPostCreate、onPostResume:这两个方法在onCreate方法和onResume方法彻底执行完毕后调用,经测试onPostCreate调用时机在onStart方法之后onResume方法之前。注意:onPostCreate方法有两个重载方法,只有savedInstanceState参数的方法会被调用,另一个两个参数的方法不会调用。在onPostCreate、onPostResume两个方法中获取控件的宽高仍然是0。
2、弹出Dialog,生命周期如何执行
不要查阅资料,直接回答——第一反应是不是执行activity的onPause方法?
是的那你就错了,单纯的创建dialog并弹出,不会执行activity的任何生命周期。如果是跳转到一个设置了窗口样式的非全屏Activity,那么原Activity就会执行onPause方法。
3、横竖屏切换时的生命周期
只有设置了android:configChanges="orientation"属性,横竖屏切换时才会调用onConfigurationChanged方法,否则不会调用该方法,而是会将Activity销毁再重建。注意:当 API >12 时,需要加入 screenSize 属性,否则屏幕切换时即使你设置了 orientation 系统也会重建 Activity !
4、Activity异常退出时的生命周期
onPause() --> onSaveInstanceState() --> onStop() --> onDestory()
需要注意的是 onSaveInstanceState() 方法与 onPause 并没有严格的先后关系,有可能在 onPause 之前,也有可能在其后面调用,但总会在 onStop() 方法之前调用。
-
关于启动模式
standard、singleTop、singleTask、singleInstance,前两者比较简单,略过。
1、singleTask。说singleTask前先来了解一下task。什么是task?task翻译为任务,可以理解为一组相互关联的activity的集合,控制界面的跳转和返回,这个task存在于一个称为back stack的数据结构中。
如果应用程序中存在A,B,C三个activity,当用户启动应用时,先启动主Activity A,接着A开启B,B开启C,这时栈中有三个Activity,并且这三个Activity默认在同一个任务(task)中。当用户按返回时,弹出C,栈中只剩A和B,再按返回键,弹出B,栈中只剩A,再继续按返回键,弹出A,任务被移除。task是可以跨应用的,这正是task存在的一个重要原因。跨应用是什么意思呢?有时为了保持用户操作的连贯性,需要把不同应用程序的Activity放在同一个任务中。例如,在我们的应用程序中的一个Activity A中点击发送邮件,会启动邮件程序的一个Activity B来发送邮件,这两个activity是存在于不同app中的,但是被系统放在一个任务中,这样当发送完邮件后,用户按back键返回,可以返回到原来的Activity A中,这样就确保了用户体验。
接下来回到singleTask。根据谷歌官方文档,如果一个Activity启动模式设置为singleTask,那么系统总会在一个新任务的最底部(root)启动这个activity,并且被这个activity启动的其他activity会和该activity同时存在于这个新任务中。如果系统中已经存在这样的一个activity则会重用这个实例,并且调用它的onNewIntent()方法。不过谷歌的官方文档描述不准确,经过测试,把Activity启动模式设置为singleTask,在启动该activity时只会把它标示为可在一个新task中启动,至于是否在一个新task中启动,还要受其他条件的限制。这个条件就是是否设置了android:taskAffinity属性并且是否已经存在了一个由它的taskAffinity属性指定名称的task。如果没有设置taskAffinity属性,那么该Activity就会和调用它的Activity处于同一task中,不会新建task;如果设置了taskAffinity属性并且taskAffinity所指定的task已存在,也不会新建task,而是检查在这个task中是否已经有了一个该Activity的实例,若有,则会重用这个task和task中的该Activity实例,并将这个task调到前台,清除位于该Activity上面的所有Activity,显示该Activity,并调用该Activity的onNewIntent()。若没有则会在这个task中创建该Activity的实例,并调用onCreate()方法;如果设置了taskAffinity属性但是taskAffinity所指定的task不存在,才会创建一个新的task,并且将该Activity启动到这个新的task中,这个新的task的名称就是taskAffinity属性的值,而且后续被该Activity启动的其他Activity也会在这个task中。(如果Activity没有设置android:taskAffinity属性,那么它会默认运行在名字为应用包名的task中)
另外还可以将两个不同应用中的singleTask模式的Activity的taskAffinity设成相同值,这样两个activity虽然不在同一应用中,却会在运行时被分配到同一任务中。
2、singleInstance。singleInstance的特点可以归结为以下三条:
- 以singleInstance模式启动的Activity具有全局单例性,即整个系统中只会存在一个该Activity实例
- 以singleInstance模式启动的Activity具有独占性,即它会独自占用一个task,被它启动的任何activity都会运行在其他task中
- 被singleInstance模式的Activity启动的其他activity,能够但不一定新建task,也可能在一个已有的task中启动
-
关于Activity数据的传递与保存
1、数据传递
使用Intent传递数据是有大小限制的,虽然官方并未详细说明,不过通过实验的方法可以测出数据大小应该被限制在1MB之内(不同手机数值也有不同,有的甚至在512KB之内),超出大小就会出现闪退、停止运行等异常。所以不要用Intent传递过大数据比如图片等。
2、数据保存
Activity 的 onSaveInstanceState() 和 onRestoreInstanceState() 并不是生命周期方法,它们不同于 onCreate() 、onPause() 等生命周期方法,它们并不一定会被触发。只有当应用遇到意外情况(如:内存不足、用户直接按 Home 键)时由系统销毁一个 Activity ,onSaveInstanceState()才会被调用。换句话说就是除非该 activity 是被用户主动销毁的,否则就会调用onSaveInstanceState()方法。通常 onSaveInstanceState() 只适合用于保存一些临时性的状态,而 onPause() 适合用于数据的持久化保存。
-
关于Scheme 跳转协议
通过scheme 跳转协议,可以实现:服务器定制化跳转 app 页面、app 可以通过 Scheme 跳转到另一个 app 页面、可以通过 h5 页面跳转 app 原生页面。scheme跳转使用方法如下:
1、AndroidManifest中设置增加拦截器(intent-filter),设置scheme
<activity
android:name=".SchemeActivity">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:scheme="wyx" />
</intent-filter>
</activity>
2、调用。如上代码我们只是简单的配置了一个android:scheme
属性(还可以设置其他详细属性,具体参考这里),所以调用起来就很简单了。
android原生调用:
startActivity(new Intent(Intent.ACTION_VIEW,Uri.parse("wyx://")));
html调用:
<a href="wyx://">跳转</a>
有了这种跳转方式 ,只要知道其他app的scheme就可以随意的跳过去了,比如打开微信和QQ:
<a href="weixin://">打开微信</a>
<a href="mqqzone://">打开QQ</a>