Activity
要想了解Activity,那么就必须要清楚Activity的生命周期,图片是最生动的,如下图:
Activity的响应时间
当前Activity所在的线程为主线程,它的响应时间为5秒,如果在当前运行的Activity中进行耗时的操作且响应时间起过5秒,那么程序就会报ANR错误。当然,有些代码只能写在Activity中,不然就运行不了(它们不是生命周期方法),比如你想要获得android系统或者硬件一的些信息,就必须在Activity中写出来,如果单独写一个工具类获得不了。
1.onCreate():
启动一个 activity时会首先调用此方法。因此,在onCreate()的方法体里,你应该初始化该activity必要的控件
2. onStart()
onStart() 方法与 onStop() 方法是相对应的,因为不管是第一次创建还是从stopped 状态恢复回来都要调用 onStart();
在onStart 方法里可以检测一些系统特征是否有效果
3. onPause()
比如记录用户的视频播放点,草稿邮件等一些重要的东西都应该在onPause() 里保存,因为onPause(), onStop(), onDestory() 这三个方法中的任意一个被执行完后 activity 所在的 process 都有可能被系统杀死(比如为了恢复系统内存)。通
常在这样的状态下,你需要处理用户数据的提交、动画处理等操作。
3. onStop()
基本上我们应该在 onStop() 方法里清除释放所有可能会导致 内存泄漏的 activity 资源;因为 onDestory() 可能不被执行,而又不太适合在 onPause() 里做太多的事情。
4. onDestory()
onDestory() 是 activity 生命周期里最后一个 回调方法,所以onDestory() 是我们释放那些有可能导致内存泄漏的资源;
通常在 onCreate() 里创建的后台 或者额外的线程对象, 都应该在 onDestory() 里得到释放。
Activity的跳转
显式意图
跳转至同一项目下的另一个Activity,直接指定该Activity的字节码即可
Intent intent = new Intent(); intent.setClass(this, Fox.class); startActivity(intent);
跳转至其他应用中的Activity,需要指定该应用的包名和该Activity的类名
Intent intent = new Intent(); //启动系统自带的拨号器应用 intent.setClassName("com.android.dialer", "com.android.dialer.DialtactsActivity"); startActivity(intent);
隐式意图
隐式意图跳转至指定Activity
Intent intent = new Intent(); //启动系统自带的拨号器应用 intent.setAction(Intent.ACTION_DIAL); startActivity(intent);
要让一个Activity可以被隐式启动,需要在清单文件的activity节点中设置intent-filter子节点
<intent-filter > <action android:name="com.fox.second"/> <data android:scheme="asd" android:mimeType="aa/bb"/> <category android:name="android.intent.category.DEFAULT"/> </intent-filter>
- action 指定动作(可以自定义,可以使用系统自带的)
- data 指定数据(操作什么内容)
- category 类别 (默认类别,机顶盒,车载电脑)
- 隐式意图启动Activity,需要为intent设置以上三个属性,且值必须与该Activity在清单文件中对三个属性的定义匹配
- intent-filter节点及其子节点都可以同时定义多个,隐式启动时只需与任意一个匹配即可
显式意图和隐式意图的应用场景
- 显式意图用于启动同一应用中的Activity
- 隐式意图用于启动不同应用中的Activity
- 如果系统中存在多个Activity的intent-filter同时与你的intent匹配,那么系统会显示一个对话框,列出所有匹配的Activity,由用户选择启动哪一个
Activity栈及启动模式:
Activity栈保存了已经启动并且还没有终止的所有的Activity,并且我们知道栈是遵从“先进后出”的规则,那么Activity栈同样也遵从这样的规则。在Android系统在资源不足时通过Activity栈来选择目前是停止状态并且比较靠近Activity栈底的 Activity被终止。
(1)standard:标准模式,调用startActivity()方法都就会产生一个新的实例。并将该Activity增加到当前Task栈中——这种模式不会启动新的Task,新的Activity将被增加到原有的Task中。
(2)singleTop:检查是否已经存在一个实例位于Activity Stack的顶部,如果存在就不产生新的实例,否则调用Activity的newInstance()方法产生一个新实例。——这种模式不会启动新的Task。
(3)singleTask:采用这种加载模式的Activity在同一个Task内只有一个实例,当系统采用singleTask模式启动目标Activity时,可分为如下三种情况:
如果将要启动的目标Activity不存在,系统将会创建目标Activity的实例,调用本应用的singleTask的Activity将它加入原来的Task栈顶,调用非本应用的singleTask的Activity则新建一个Task将singleTask的Activity加入新建Task的栈顶。
如果将要启动的目标Activity已经位于Task栈顶,此时与singleTop模式的行为相同。
如果将要启动的目标Activity已经存在,但没有位于Task栈顶,系统将会把位于该Activity上面的所有Activity移出Task栈,从而使得目标Activity转入栈顶。即如果Activity发现已经存在时,会销毁其上的Activity,然后调用onNewIntent。(不管是调用其他应用的singleTask的Activity还是本应用的singleTask的Activity)。
建议:如果该Activity的类型不是LAUNCHER,最好不要设为singleTask。
用处: 那 么singleTask的这些特性有什么用处?我们举一个例子,浏览器就是一个singleTask的例子,启动一个浏览器,在Android中是一个比 较沉重的过程,它需要做很多初始化的工作,并且会有不小的内存开销。如果有多个应用都来请求打开网页,那么系统就不会不堪重负。因此,如果浏览器采用 singleTask模式,如果有多个请求打开网页的请求,都会在一个Task中响应,这样就会避免以上的情况。
SingleTask的例子:浏览器的browser activity设置了SingleTask只运行在它自己的task中,如果Browser的task现在正在后台当中(task B),而我们的app(task A)的正要打开这个activity,这个task就会被直接移到前台接收我们的intent。
(4)singleInstance:这种加载模式下,系统保证无论从哪个Task中启动目标Activity,只会创建一个目标Activity实例,并会使用一个全新的Task栈来装载该Activity实例。 当系统采用singleInstance模式启动目标Activity时可分为如下两种情况:
如果将要启动的目标Activity不存在,系统会先创建一个全新的Task,再创建目标Activity的实例,并将它加入新的Task的栈顶。
如果将要启动的目标Activity已经存在,无论它位于哪个应用程序中,无论它位于哪个Task中,系统将会把该Activity所在的Task转到前台,从而使用该Activity显示出来。
Activity的4种状态
Activity的生命周期指Activity从启动到销毁的过程,Activity有4种状态:
(1)活动(Active)状态:这时候Activity处于栈顶,且是可见的,有焦点的,能够接收用户输入前 景Activity。Runtime将试图不惜一切代价保持它活着,甚至杀死其他Activity以确保它有它所需的资源。当另一个Activity变成Active时,当前 的将变成Paused状态。
(2)暂停(Paused)状态:在 某些情况下,你的Activity是可见的,但没有焦 点,在这时候,Actvity处于Paused状态。例如,如果有一个透明或非全屏幕上的Activity在你的Actvity上面,你的 Activity将。当处于Paused状态时,该Actvity仍被认为是Active的,但是它不接受用户输入事件。在极端情况下,Runtime将 杀死Paused Activity,以进一步回收资源。当一个Actvity完全被遮住时,它将进入Stopped状态。
(3)停止(Stopped)状态:当Activity是不可见的时,Activity处于Stopped状态。Activity将继续保留在内存中保持当前的所有状态和成员信息,假 设系统别的地方需要内存的话,这时它是被回收对象的主要候选。当Activity处于Stopped状态时,一定要保存当前数据和当前的UI状态,否则一 旦Activity退出或关闭时,当前的数据和UI状态就丢失了。
(4)非活动(Inactive)状态:Activity被杀掉以后或者被启动以前,处于Inactive状态。这时Activity已被移除从Activity堆栈中,需要重新启动才可以显示和使用。
Activity的生命周期使用
(1)全生命周期:
全生命周期是从Activity建立到销毁的全部过程,始于onCreate(),结束于onDestroy()。开发者通常在onCreate()中初始化用户界面, 分配引用类变量,绑定数据控件,并创建服务和线程等Activity所能使用的全局资源和状态,并在onDestroy()中释放这些资源,并确保所有外部连接被关闭,如网络或数据库的连接等;在一些极端情况下,Android系统会直接终止进程,而不会先调用onDestroy()。
为了避免创造短期对象和增加垃圾收集的时间,以致对用户体验产生直接影响。如果你的Activity需要创建一些对象的话,最好在onCreate方法中创建,因为它在一个Activity的完整生命周期中只被调用一次。
使用OnCreate方法来初始化你的Activity:初始化的用户界面,分配引用类变量,绑定数据控件,并创建服务和线程。在OnCreate方法传 递的对象Bundle包含最后一次调用onSaveInstanceState保存的UI状态。你可以使用这个Bundle恢复用户界面到以前的状态,无 论是在OnCreate方法或通过覆盖onRestoreInstanceStateMethod方法。
覆盖onDestroy方法来清理OnCreate中创建的任何资源,并确保所有外部连接被关闭,例如网络或数据库的联系。
例如:某个Activity有一个在后台运行的线程,用于从网络下载数据,则该Activity可以在onCreate()中创建线程,在onDestory()中停止线程
(2)可视生命周期:
可视生命周期是Activity在界面上从可见到不可见的过程,开始于onStart(),结束于onStop()。在极端情况下,系统会直接销毁一个Activity,而不先调用onStop,即使它处于可见状态。在这个时间里,活动对用户是可见的,但是它有可能不具有焦点,或者它可能被部分遮住了。在一个Activity完整的生命周期中可能会经过几个Activity可见的生命周期,因为你的Activity可 能会经常在前台和后台之间切换。在极端情况下,Runtime将杀掉一个Activity即使它在可见状态并且并不调用onStop方法。
OnStop方法用于暂停或停止动画,线程,定时器,服务或其他专门用于更新用户界面程序。当用户界面是再次可见时,使用OnStart(或onRestart)方法来恢复或重新启动这些程序,。
onRestart方法优先于onStart被调用当一个Activity被重现可见时,使用它你可以实现一些Activity重新可见时的特殊的处理。
例如:可以在onStart中注册一个Intent Receiver来监听数据变化导致UI的变动,当不再需要显示时候,可以在onStop()中注销它。onStart(),onStop()都可以被多次调用,因为Activity随时可以在可见和隐藏之间转换。
OnStart / OnStop方法也被用来注册和注销专门用于更新用户界面Intent接收者。
(3)活动(前台)生命周期
活动生命周期是Activity在屏幕最上层,并能够与用户交互的阶段,并且正在接收用户的输入事件。开始于onResume(),结束于onPause()。在Activity的状态变换过程中onResume()和onPause()经常被调用,因此这两个方法中的代码应该写得简单、高效些,以提高性能,以保证在前台和后台之间进行切换的时候应用能够保持响应。当一个新的Actvity启 动,或该设备进入休眠状态,或失去焦点,Activity活跃的生命周期就结束。
尽量在onPause和onResume方法中执行较量轻的代码以确保您的应用程序能够快速响应Acitvity在前台和后台之间切换。
在调用onPause之前,onSaveInstanceState会被调用。这个方法提供了一个机会保存当前的UI状态到Bundle当中。 Bundle信息将会被传递到OnCreate和onRestoreInstanceState方法。使用onSaveInstanceState保存 UI状态(如检查按钮状态,用户焦点,未提交用户输入)能够确保目前相同的用户界面当Activity下次被激活时。在Activity活跃生命周期中, 你可以安全地认onSaveInstanceState和onPause将被调到即使当前进程将终止。
总的来说,在生命周期里通过重写Activity生命周期回调方法,你可以监控以上三个嵌套的方法循环。
activity的横竖屏切换
1、不设置Activity的android:configChanges时,切屏会重新调用各个生命周期,切横屏时会执行一次,切竖屏时会执行两次
2、设置Activity的android:configChanges="orientation"时,切屏还是会重新调用各个生命周期,切横、竖屏时只会执行一次
3、设置Activity的android:configChanges="orientation|keyboardHidden"时,切屏不会重新调用各个生命周期,只会执行onConfigurationChanged方法
某些操作对应下的生命周期流程
1) 启动Activity:onCreate()->onStart()->onResume()->Activityis running
2) 按back键返回:onPause()->onStop()->onDestroy() 再次启动时:onCreate()->onStart()->onResume()->Activityis running
3). 按home键返回:onPause()->onStop() 再次启动时:onRestart()->onStart()->onResume()->Activity isrunning
4) 切换到别的Activity(当前Activity不finish),或者采用这个,启动程序进入Activity,按Home键进入桌面,然后长按Home建点击该应用重新进入Activity:onPause()->onStop() 再次启动时:onRestart()->onStart()->onResume()->Activityis running
5) 切换到别的Activity(当前Activity finish):onPause()->onStop()->onDestroy() 再次启动时:onCreate()->onStart()->onResume()->Activity isrunning
6)然后按挂机键,进入锁屏界面,然后从锁屏界面返回Activity:onPause()->onResume()
7)切换到另一个Activity对话框界面,然后按返回键返回原来的Activity:onPause()->onResume()