Activity,Fragment,Service生命周期

2022-01-20  本文已影响0人  小杨不想努力了

参考资料:
《Android开发艺术探索》
https://lrh1993.gitbooks.io/android_interview_guide/content/android/basis/service.html

  1. Activity,Fragment,Service生命周期

    • Activity

      在正常情况下,一个Activity从启动到结束的生命周期如下:

      onCreate()->onStart()->onResume()->onPause()->onStop()->onDestory()(还有一个onRestart()没有调用)

      1. onCreate()

        当Activity第一次创建时会被调用,用来初始化一些工作,比如调用setContentView去加载界面布局资源,初始化Activity所需的数据。

      2. onRestart()

        表示Activity正在重新启动。一般情况下,当当前Activity从不可见重新变为可见状态时,onRestart()就会被调用。这种情形一般是用户行为导致的,比如用户按Home键切换到桌面或打开了另一个新的Activity,接着用户又回到了这个Actvity,就会出现这种情况。

      3. onStart()

        表示Activity正在被启动,即将开始,这时Activity已经出现了,但是还没有出现在前台,无法与用户交互。这个时候可以理解为Activity已经显示出来, 但是我们还看不到。

      4. onResume()

        表示Activity已经可见了,并且出现在前台并开始活动。需要和onStart()区分,onStart的时候 Activity还在后台,onResume的时候Activity才显示到前台。

      5. onPause()

        表示 Activity正在停止,仍可见,正常情况下,紧接着onStop就会被调用。在特殊情况下,如果这个时候快速地回到当前Activity,那么onResume就会被调用(极端情况)。onPause中不能进行耗时操作,会影响到新Activity的显示。因为onPause必须执行完,新的Activity的onResume才会执行。

      6. onStop()

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

      7. onDestory()

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

      四种状态:

      1. 运行状态: Activity在此状态时处于屏幕最前端,它是可见、有焦点的,可以与用户进行交互。如单击、长按等事件。即使出现内存不足的情况,Android也会先销毁栈底的Activity,来确保当前的Activity正常运行。

      2. 暂停状态:

        当一个活动不再处于栈顶的位置,但仍然可见,弹出一个对话框或者一个不能占满屏幕的活动都会导致前一个活动处于暂停状态,系统继续维护其内部状态,它仍然可见,但它已经失去了焦点,故不可与用户交互。系统也不会轻易回收这样的活动,除非是内存极低的情况(回收可见的活动都会造成极不好的用户体验)。

      3. 停止状态:

        当一个活动不处于栈顶位置,且完全不可见的时候,就进入停止状态,但仍然保留着当前的状态和成员信息,当内存较低时系统会回收这样的活动。

      4. 销毁状态:

        当一个活动从栈中移除后就变成销毁状态,系统会回收这样的活动

      生命周期分析:

      1. Activity1打开Activity2

        旧的先pause,新的才创建

        https://note.youdao.com/yws/public/resource/3c8c773a3d105f8e5fa5b9d7a0ef31ad/xmlnote/2FD62DB1D60646B896BA300401802DAF/5097
      2. 资源相关的系统配置发生变化(屏幕翻转)

        在横竖屏切换的过程中,会发生Activity被销毁并重建的过程。

        在了解这种情况下的生命周期时,首先应该了解这两个回调:onSaveInstanceStateonRestoreInstanceState

        在Activity由于异常情况下终止时,系统会调用onSaveInstanceState来保存当前Activity的状态。这个方法的调用是在onStop之前,它和onPause没有既定的时序关系,该方法只在Activity被异常终止的情况下调用。当异常终止的Activity被重建以后,系统会调用onRestoreInstanceState,并且把Activity销毁时onSaveInstanceState方法所保存的Bundle对象参数同时传递给onRestoreInstanceState和onCreate方法。因此,可以通过onRestoreInstanceState方法来恢复Activity的状态,该方法的调用时机是在onStart之后。其中onCreate和onRestoreInstanceState方法来恢复Activity的状态的区别: onRestoreInstanceState回调则表明其中Bundle对象非空,不用加非空判断。onCreate需要非空判断。建议使用onRestoreInstanceState。

        img

        横竖屏切换的生命周期:

        onPause()->onSaveInstanceState()-> onStop()->onDestroy()->onCreate()->onStart()->onRestoreInstanceState()->onResume()

        可以通过在AndroidManifest文件的Activity中指定如下属性:

        android:configChanges = "orientation| screenSize"
        

        来避免横竖屏切换时,Activity的销毁和重建,而是回调了下面的方法:

        @Override
        public void onConfigurationChanged(Configuration newConfig) {
         super.onConfigurationChanged(newConfig);
        }
        

        Android 3.2 (API 级别 13)以前

        • 不设置Activity的android:configChanges时,切屏会重新调用各个生命周期,切横屏时会执行一次,切竖屏时会执行两次

        • 设置Activity的android:configChanges="orientation"时,切屏还是会重新调用各个生命周期,切横、竖屏时只会执行一次

        • 设置Activity的android:configChanges="orientation|keyboardHidden"时,切屏不会重新调用各个生命周期,只会执行onConfigurationChanged方法

        从 Android 3.2 (API级别 13)开始

        • 不设置Activity的android:configChanges,或设置Activity的android:configChanges="orientation"`,或设置Activity的android:configChanges="orientation|keyboardHidden",切屏会重新调用各个生命周期,切横屏时会执行一次,切竖屏时会执行一次。

        • 配置 android:configChanges="orientation|keyboardHidden|screenSize",才不会销毁 activity,且只调用 onConfigurationChanged方法。

      3. Activity A启动Activity B它们的生命周期变化(及设置Activity的透明度)

        1. 当Activity B 覆盖A导致A完全不可见时:

          //【1】部署程序
          D/MainActivity: onCreate------A
          D/MainActivity: onStart-------A
          D/MainActivity: onResume------A
          
          //【2】点击A中的按钮开始跳转到B
          D/MainActivity: onPause-------A
          D/SecondActivity: onCreate----B
          D/SecondActivity: onStart-----B
          D/SecondActivity: onResume----B
          D/MainActivity: onStop--------A
          
          //【3】然后点击返回键从B返回A
          D/SecondActivity: onPause-----B
          D/MainActivity: onRestart-----A
           onStart-------A
          D/MainActivity: onResume------A
          D/SecondActivity: onStop------B
          D/SecondActivity: onDestroy---B
          
        2. 当Activity B背景被设置为透明(相当于发生跳转后,A部分可见)

          //【1】部署程序
          D/MainActivity: onCreate------A
          D/MainActivity: onStart-------A
          D/MainActivity: onResume------A
          
          //【2】点击A中的按钮开始跳转到B
          D/MainActivity: onPause-------A
          D/SecondActivity: onCreate----B
          D/SecondActivity: onStart-----B
          D/SecondActivity: onResume----B
          
          //【3】然后点击返回键从B返回A
          D/SecondActivity: onPause-----B
          D/MainActivity: onResume------A
          D/SecondActivity: onStop------B
          D/SecondActivity: onDestroy---B
          

          总结:当A启动B时,并且启动之后A还处于部分可见状态,当启动完B之后并不回调A的onStop()方法。

      资源内存不足导致活动被杀死:

      当系统内存不足的时候,系统就会按照优先级的大小去杀死一些活动,并在后续通过上面onSaveInstanceState和onRestoreInstanceState方法来恢复数据。优先级按照状态依次是:运行状态,暂停状态,停止状态。一般最有可能是停止状态的活动被杀了。所以一些后台工作就尽量放在service中,提高优先级,防止被杀死。脱离四大组件的活动容易被杀死。

      几个特殊的方法:

      1. onWindowFocusChanged方法:在Activity窗口获得或失去焦点时被调用,例如创建时首次呈现在用户面前;当前Activity被其他Activity覆盖;当前Activity转到其他Activity或按Home键回到主屏,自身退居后台;用户退出当前Activity。以上几种情况都会调用onWindowFocusChanged,并且当Activity被创建时是在onResume之后被调用,当Activity被覆盖或者退居后台或者当前Activity退出时,它是在onPause之后被调用。

      2. onSaveInstanceState:

        • 在Activity被覆盖或退居后台之后,系统资源不足将其杀死,此方法会被调用;

        • 在用户改变屏幕方向时,此方法会被调用;

        • 在当前Activity跳转到其他Activity或者按Home键回到主屏,自身退居后台时,此方法会被调用。

          第一种情况我们无法保证什么时候发生,系统根据资源紧张程度去调度;第二种是屏幕翻转方向时,系统先销毁当前的Activity,然后再重建一个新的,调用此方法时,我们可以保存一些临时数据;第三种情况系统调用此方法是为了保存当前窗口各个View组件的状态。这个方法会在 onStop() 前被触发,但系统并不保证是否在 onPause() 之前或者之后触发。

      3. onRestoreInstanceState:

        • 在Activity被覆盖或退居后台之后,系统资源不足将其杀死,然后用户又回到了此Activity,此方法会被调用;

        • 在用户改变屏幕方向时,重建的过程中,此方法会被调用。我们可以重写此方法,以便可以恢复一些临时数据。onRestoreInstanceState的调用顺序是在onStart之后。

    • Fragment

      可以简单的理解为,Fragment是显示在Activity中的Activity。它可以显示在Activity中,然后它也可以显示出一些内容。因为它拥有自己的生命周期,可以接受处理用户的事件,并且你可以在一个Activity中动态的添加,替换,移除不同的Fragment,因此对于信息的展示具有很大的便利性。

      因为Fragment是依附于Activity存在的,因此它的生命周期受到Activity的生命周期影响

      举个例子:如果Activity是暂停状态,其中所有的Fragment都是暂停状态;如果Activity是stopped状态,这个Activity中所有的Fragment都不能被启动;如果Activity被销毁,那么它其中的所有 Fragment都会被销毁。但是,当Activity在活动状态,可以独立控制Fragment的状态,比如加上或者移除 Fragment。 当这样进行fragment transaction(转换)的时候,可以把fragment放入Activity的back stack中,这样用户就可以进行返回操作。

      https://note.youdao.com/yws/public/resource/3c8c773a3d105f8e5fa5b9d7a0ef31ad/xmlnote/8A347307CD604C4BB8F665DF76D3A790/3439

      Fragment比Activity多了几个生命周期的回调方法:

      • onAttach(Activity)

        当Fragment与Activity发生关联时调用。

      • onCreateView(LayoutInflater, ViewGroup,Bundle)

        创建该Fragment的视图

      • onActivityCreated(Bundle)

        当Activity的onCreate方法返回时调用

      • onDestoryView()

        与onCreateView对应,当该Fragment的视图被移除时调用

      • onDetach()

        与onAttach相对应,当Fragment与Activity关联被取消时调用

      注意:除了onCreateView,其他的所有方法如果你重写了,必须调用父类对于该方法的实现,就是Super。不能去掉。

    • service

      Service是Android程序中四大基础组件之一,它和Activity一样都是Context的子类, 只不过它没有UI界面,是在后台运行的组件。 Service是Android中实现程序后台运行的解决方案,它非常适用于去执行那些不需 要和用户交互而且还要求长期运行的任务。Service默认并不会运行在子线程中,它 也不运行在一个独立的进程中,它同样执行在UI线程中,因此,不要在Service中执行耗时的操作,除非你在Service中创建了子线程来完成耗时操作。

      1. OnCreate()

        系统在service第一次创建时执行此方法,来执行只运行一次的初始化工作。如果 service已经运行,这个方法不会被调用。

      2. onStartCommand()

        每次客户端调用startService()方法启动该Service都会回调该方法(多次调用)。一旦这个方法执行,service就启动并且在后台长期运行。通过调用stopSelf()或stopService()来停止服务。

      3. onBind()

        当组件调用bindService()想要绑定到service时(比如想要执行进程间通讯)系统调用此方法(一次调用,一旦绑定后,下次再调用bindService()不会回调该方法)。在实现中,你必须提供一个返回一个IBinder来以使客户端能够使用它与service通讯,你必须总是实现这个方法,但是如果你不允许绑定,那么你应返回null。

      4. onUnbind()

        当前组件调用unbindService(),想要解除与service的绑定时系统调用此方法(一次调用,一旦解除绑定后,下次再调用unbindService()会抛出异常)。

      5. onDestory()

        系统在service不再被使用并要销毁时调用此方法(一次调用)。service应在此方法中释放资源,比如线程,已注册的侦听器,接收器等等。这是service收到的最后一个调用。

        img

        三种启动情况下的生命周期:

        1. startService / stopService

          生命周期顺序:onCreate->onStartCommand->onDestroy

          如果一个Service被某个Activity 调用 Context.startService方法启动,那么不管是否有Activity使用bindService绑定或unbindService解除绑定到该Service,该Service都在后台运行,直到被调用stopService,或自身的stopSelf方法。当然如果系统资源不足,android系统也可能结束服务,还有一种方法可以关闭服务,在设置中,通过应用->找到自己应用->停止。

          注意点:

          • 第一次 startService 会触发 onCreate 和 onStartCommand,以后在服务运行过程中,每次 startService 都只会触发 onStartCommand

          • 不论 startService 多少次,stopService 一次就会停止服务

        2. bindService / unbindService

          生命周期顺序:onCreate->onBind->onUnBind->onDestroy

          如果一个Service在某个Activity中被调用bindService方法启动,不论bindService被调用几次,Service的onCreate方法只会执行一次,同时onStartCommand方法始终不会调用。

          当建立连接后,Service会一直运行,除非调用unbindService来接触绑定、断开连接或调用该Service的Context不存在了(如Activity被Finish——即通过bindService启动的Service的生命周期依附于启动它的Context),系统在这时会自动停止该Service。

          注意点:

          • 第一次 bindService 会触发 onCreate 和 onBind,以后在服务运行过程中,每次 bindService 都不会触发任何回调
        3. 混合型(上面两种方式的交互)

          当一个Service在被启动(startService)的同时又被绑定(bindService),该Service将会一直在后台运行,并且不管调用几次,onCreate方法始终只会调用一次,onStartCommand的调用次数与startService调用的次数一致(使用bindService方法不会调用onStartCommand)。同时,调用unBindService将不会停止Service,必须调用stopService或Service自身的stopSelf来停止服务。

        在什么情况下使用 startService 或 bindService 或 同时使用startService 和 bindService?

        • 如果你只是想要启动一个后台服务长期进行某项任务那么使用 startService 便可以了。

        • 如果你想要与正在运行的 Service 取得联系,那么有两种方法,一种是使用 broadcast ,另外是使用 bindService ,前者的缺点是如果交流较为频繁,容易造成性能上的问题,并且 BroadcastReceiver 本身执行代码的时间是很短的(也许执行到一半,后面的代码便不会执行),而后者则没有这些问题,因此我们肯定选择使用 bindService(这个时候你便同时在使用 startService 和 bindService 了,这在 Activity 中更新 Service 的某些运行状态是相当有用的)。

        • 如果你的服务只是公开一个远程接口,供连接上的客服端(android 的 Service 是C/S架构)远程调用执行方法。这个时候你可以不让服务一开始就运行,而只用 bindService ,这样在第一次 bindService 的时候才会创建服务的实例运行它,这会节约很多系统资源,特别是如果你的服务是Remote Service,那么该效果会越明显(当然在 Service 创建的时候会花去一定时间,你应当注意到这点)。

        注意:

        • Service不运行在一个独立的进程中,它同样执行在UI线程中,因此,在Service中创建了子线程来完成耗时操作。
        • 当Service关闭后,如果在onDestory()方法中不关闭线程,你会发现我们的子线程进行的耗时操作是一直存在的,此时关闭该子线程的方法需要直接关闭该应用程序。因此,在onDestory()方法中要进行必要的清理工作。
上一篇下一篇

猜你喜欢

热点阅读