Activity总结

一、Activity的生命周期

activity应该是我们初学android就接触的,而它的生命周期更是重中之重,掌握activity的生命周期也是学好android的基础

这张图片可谓是非常经典,应该学习android的人都见过,下面讲一一讲解各个方法:

(1) onCreate():在activity创建时会被调用,通常会在其中加载布局,初始化控件。

(2) onRestart():当当前界面重新启动时会被调用,可是能是用户回到桌面又切换回来了,也可能是用户打开了一个新的Activity又切换回来了。

(3) onStart(): Activity正在被启动,即将开始,这时Activity已经出现了,但是还没有出现在前台,无法与用户交互(与onResume的主要区别)

(4) onResume():界面可见

(5) onPause(): Activity正在停止,仍可见。onPause中不能进行耗时操作,会影响到新Activity的显示。因为onPause必须执行完,新的Activity的onResume才会执行。

(6) onStop():Activity即将停止,不可见,位于后台。可以做稍微重量级的回收工作,同样不能太耗时。

(7) onDestory():Activity即将销毁,这是Activity生命周期的最后一个回调,可以做一些回收工作和最终的资源回收。

从ActivityA跳转到ActivityB的过程

ActivityA onPause() -->ActivityB onCreate() -->ActivityB onStart()  --> ActivityB onResume() --> ActivityA onStop()

onPostCreate:一般不实现这个方法,当程序的代码开始运行时,它调用系统做最后的初始化工作。

特别注意:当ActivityB为透明界面或者Dialog样式时不会调用ActivityA的onStop()

异常生命周期:

1.横竖屏切换

如果没有在AndroidManifest中配置以下属性,Activity将会在屏幕旋转时重建

android:configChanges = "orientation| screenSize"

当Activity异常销毁时会调用onSaveInstanceState()方法来保存界面状态,会将之存储到Bundle对象中,系统会根据该界面是否会重现来决定调不调用该方法,该方法的调用时机不确定,但是如果要调用就一定发生在onStop方法之前,但并不保证发生在onPause的前面还是后面。

当重建Activity重建时会回调onRestoreInstanceState()方法,传入onSaveInstanceState()保存的Bundle对象。这个方法在onStart 和 onPostCreate之间调用,在onCreate中也可以状态恢复,但是有时候需要布局初始化完成后再恢复状态。Google官方建议在onRestoreInstanceState()中恢复,因为此方法一旦被调用就可以保证Bundle对象不为null。

当出现下列情况时会调用保存和恢复方法:

  1. 当用户按下HOME键时
  2. 长按HOME键,选择运行其他的程序时
  3. 锁屏时
  4. 从activity A中启动一个新的activity时
  5. 屏幕方向切换时

 2.资源内存不足导致优先级低的Activity被杀死

Activity优先级的划分和下面的Activity的三种运行状态是对应的。

(1) 前台Activity——正在和用户交互的Activity,优先级最高。

(2) 可见但非前台Activity——比如Activity中弹出了一个对话框,导致Activity可见但是位于后台无法和用户交互。

(3) 后台Activity——已经被暂停的Activity,比如执行了onStop,优先级最低。

当系统内存不足时,会按照上述优先级从低到高去杀死目标Activity所在的进程。这种情况下界面存储和恢复过程和上述情况一致,生命周期情况也一样。

Activity的三种运行状态

①Resumed(活动状态)

又叫Running状态,正在显示的界面

②Paused(暂停状态)

这是一个比较不常见的状态。这个Activity在屏幕上是可见的,但是并不是在屏幕最前端的那个Activity。比如有另一个非全屏或者透明的Activity是Resumed状态,没有完全遮盖这个Activity。

③Stopped(停止状态)

当Activity完全不可见时,此时Activity还在后台运行。

二、Activity的启动模式与特点

(1)标准模式(Standard

系统的默认模式,每次启动一个Activity都会重新创建一个新的Activity实例,不管是否已经存在。并且谁启动了这个Activity,那么这个Activity就会运行在启动它的Activity所在的任务栈中。

特别注意:如果我们用ApplicationContext来启动标准模式的Activity就会报错,因为它没有所谓的任务栈,必须给Activity添加FLAG_ACTIVITY_NEW_TASK标志位。

(2)栈顶复用模式(singleTop

在这个模式中,Activity还是会创建在启动它的Activity的任务栈中,但是如果它已经位于栈顶,那么就不会重复创建,并且它的onNewIntent()会被调用,可用于传递消息,但是要注意它的生命周期方法onCreate()等等不会被调用。如果它并不位于栈顶,如ABC,这时启动B,还是会创建一个新的实例,和standard一样。

可以用于避免手抖打开多个界面

(3)栈内复用模式(singleTask

在这个模式中,比如启动Activity A,首先系统会寻找是否存在A想要的任务栈:如果存在,就看任务栈中是否有A,如果有就清除A上面的所有Activity,把A推到栈顶。

特别注意:如果存在A的任务栈,那么任务栈自动回切换到前台

singleTask和taskAffinity配合使用,指定开启的Activity加入到哪个栈中

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

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

应用场景:

singleTask适合作为程序入口点。例如浏览器的主界面。不管从多少个应用启动浏览器,只会启动主界面一次,其余情况都会走onNewIntent(),并且会清空主界面上面的其他页面。之前打开过的页面,打开之前的页面就ok,不再新建。

(4)单实例模式(singleInstance

加强版的singleTAsk,启动时,无论从哪里启动都会给A创建一个唯一的任务栈,后续的创建都不会再创建新的A,除非A被销毁了。singleInstance不要用于中间页面,如果用于中间页面,跳转会有问题,比如:A -> B (singleInstance) -> C,完全退出后,再次启动,首先打开的是B。

 应用场景:

 singleInstance适合需要与程序分离开的页面。例如闹铃提醒,将闹铃提醒与闹铃设置分离。

Activity的Flags

Activity的Flags很多,这里介绍几种常用的,用于设定Activity的启动模式。可以在启动Activity时,通过Intent的addFlags()方法设置。

(1)FLAG_ACTIVITY_NEW_TASK 其效果与指定Activity为singleTask模式一致。

(2)FLAG_ACTIVITY_SINGLE_TOP 其效果与指定Activity为singleTop模式一致。

(3)FLAG_ACTIVITY_CLEAR_TOP 具有此标记位的Activity,当它启动时,在同一个任务栈中所有位于它上面的Activity都要出栈。如果和singleTask模式一起出现,若被启动的Activity已经存在栈中,则清除其之上的Activity,并调用该Activity的onNewIntent方法。如果被启动的Activity采用standard模式,那么该Activity连同之上的所有Activity出栈,然后创建新的Activity实例并压入栈中。

三、Activity卡顿原因

(1)内存泄漏导致内存占用较高,导致JVM频繁触发GC。

导致内存泄漏的原因有一下几个

1.错误的单例

单例的生命周期和应用一样长,如果持有一个短生命周期对象的引用的话就会造成内存泄漏

2.创建了非静态内部类的静态实例

非静态内部类隐性持有外部类的对象,且静态示例存在周期较长

3.资源忘记关闭

BraodcastReceiver、ContentObserver、File、Cursor、Stream、Bitmap

(2)加载大数据,占用太多内存,同样导致JVM频繁GC。

解决办法:主要是Bitmap占用太多内存。可以通过根据需要显示的Bitmap宽高设定采样率来压缩图片。另外,通过采用LRUCache方法避免。如果是其他的大数据比如3D模型数据,可以通过使用Native空间,使用ByteBuffer.allocate(size);

(3)UI线程做耗时任务(数据库操作,数据计算等),1秒绘制60帧才不会卡顿,即16.6ms要刷新一次才不会卡顿。

解决方法:另起线程做耗时任务。

(4)UI OverDraw。

(5)在包含ImageView的ListView中,等滑动停止后加载图片。

四、Activity的启动过程

可将其分为6个过程:

1 使用代理模式启动到ActivityManagerService中执行;

2 创建ActivityRecord到mHistory记录中;

3 通过socket通信到Zgote相关类创建process

4 通过ApplicatonThreadActivityManagerService建立通信;

5 ActivityManagerService通知ActivityThread启动Activity的创建;

6 ActivityThread创建Activity加入到mActivities中并开始调度Activity执行

注: 整个应用程序的启动过程要执行很多步骤,但是整体来看,主要分为以下五个阶段:

   应用程序是由Launcher启动起来的,其实,Launcher本身也是一个应用程序,其它的应用程序安装后,就会Launcher的界面上出现一个相应的图标,点击这个图标时,Launcher就会对应的应用程序启动起来。

       一. Launcher通过Binder进程间通信机制通知ActivityManagerService,它要启动一个Activity;

       二. ActivityManagerService通过Binder进程间通信机制通知Launcher进入Paused状态;

       三. :Launcher通过Binder进程间通信机制通知ActivityManagerService,它已经准备就绪进入Paused状态,于是ActivityManagerService就创建一个新的进程,用来启动一个ActivityThread实例,即将要启动的Activity就是在这个ActivityThread实例中运行;

       四. ActivityThread通过Binder进程间通信机制将一个ApplicationThread类型的Binder对象传递给ActivityManagerService,以便以后ActivityManagerService能够通过这个Binder对象和它进行通信;

       五. ActivityManagerService通过Binder进程间通信机制通知ActivityThread,现在一切准备就绪,它可以真正执行Activity的启动操作了。

如何加速Activity的启动

1.视图优化

  1. 尽量精简布局,减少布局层数,使用viewStub、include、merge
  2. 谨慎选用布局 如相对布局和线性布局的选用
  3. 避免太繁复的动画,onDraw中不要创建大量临时对象
  4. 列表中的视图复用,异步加载,分页加载
  5. 使用Hierarchy Viewer、Layoutopt
  6. 页面分模块加载

2.网络优化

  1. 页面开始时先取用缓存数据再进行网络请求,更新数据
  2. 使用线程池管理线程
  3. 不要短时间内创建大量线程,尽量流出更多时间先把界面显示出来
  4. Fragment懒加载

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

幽蓝丶流月

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值