zoukankan      html  css  js  c++  java
  • Activity和Service的生命周期(图)*

    1、Activity的生命周期

    情形一、一个单独的Activity的正常的生命过程是这样的:onCreate->onStart->onPause->onStop->onDestroy。例如:运行一个Activity,进行了一些简单操作(不涉及页面的跳转等),然后按返回键结束。

    情形二、有两个Activity(a和b),一开始显示a,然后由a启动b,然后在由b回到a,这时候a的生命过程应该是怎么样的呢(a被b完全遮盖)?

    a经历的过程为onCreate->onStart->onResume->onPause->onStop->onRestart->onStart->onResume。这个过程说明了图中,如果Activity完全被其他界面遮挡时,进入后台,并没有完全销毁,而是停留在onStop状态,当再次进入a时,onRestart->onStart->onResume,又重新恢复。

    情形三、基本情形同二一样,不过此时a被b部分遮盖(比如给b添加个对话框主题 android:theme="@android:style/Theme.Dialog")

    a经历的过程是:onCreate->onStart->onResume->onPause->onResume

    所以当Activity被部分遮挡时,Activity进入onPause,并没有进入onStop,从Activity2返回后,执行了onResume

    情形四、 打开程序,启动a,点击a,启动AlertDialog,按返回键从AlertDialog返回。

    a经历的过程是:onCreate->onStart->onResume

    当启动和退出Dialog时,Activity的状态始终未变,可见,Dialog实际上属于Acitivity内部的界面,不会影响Acitivty的生命周期。

    一个详细的生命周期实例启动A,在A中打开B,点击Back键返回:

    A:onCreat()->A:onStart() ->A:onResume()->A:onPause() ->B:onCreate()->B:onStart()->B:onResume()->A:onStop()

    B:onPause()->A:onRestart()->A:onStart()->A:onResume()->B:onStop()->B:onDestroy()

    触发onSaveInstanceState和onRestoreInstanceState的时机

    先看Application Fundamentals上的一段话:
     
     Android calls onSaveInstanceState() before the activity becomes vulnerable to being destroyed by the system, but does not bother calling it when the instance is actually being destroyed by a user action (such as pressing the BACK key)
     
    从这句话可以知道,当某个activity变得“容易”被系统销毁时,该activity的onSaveInstanceState就会被执行,除非该activity是被用户主动销毁的,例如当用户按BACK键的时候。
    注意上面的双引号,何为“容易”?言下之意就是该activity还没有被销毁,而仅仅是一种可能性。这种可能性有哪些?通过重写一个activity的所有生命周期的onXXX方法,包括onSaveInstanceState和onRestoreInstanceState方法,我们可以清楚地知道当某个activity(假定为activity A)显示在当前task的最上层时,其onSaveInstanceState方法会在什么时候被执行,有这么几种情况:

    1、当用户按下HOME键时。
    这是显而易见的,系统不知道你按下HOME后要运行多少其他的程序,自然也不知道activity A是否会被销毁,故系统会调用onSaveInstanceState,让用户有机会保存某些非永久性的数据。以下几种情况的分析都遵循该原则

    2、长按HOME键,选择运行其他的程序时。

    3、按下电源按键(关闭屏幕显示)时。

    4、从activity A中启动一个新的activity时。

    5、屏幕方向切换时,例如从竖屏切换到横屏时。
    在屏幕切换之前,系统会销毁activity A,在屏幕切换之后系统又会自动地创建activity A,所以onSaveInstanceState一定会被执行
     
    总而言之,onSaveInstanceState的调用遵循一个重要原则,即当系统“未经你许可”时销毁了你的activity,则onSaveInstanceState会被系统调用,这是系统的责任,因为它必须要提供一个机会让你保存你的数据(当然你不保存那就随便你了)。
     

    至于onRestoreInstanceState方法,需要注意的是,onSaveInstanceState方法和onRestoreInstanceState方法“不一定”是成对的被调用的,(本人注:我昨晚调试时就发现原来不一定成对被调用的!)
     
    onRestoreInstanceState被调用的前提是,activity A“确实”被系统销毁了,而如果仅仅是停留在有这种可能性的情况下,则该方法不会被调用,例如,当正在显示activity A的时候,用户按下HOME键回到主界面,然后用户紧接着又返回到activity A,这种情况下activity A一般不会因为内存的原因被系统销毁,故activity A的onRestoreInstanceState方法不会被执行

    另外,onRestoreInstanceState的bundle参数也会传递到onCreate方法中,你也可以选择在onCreate方法中做数据还原。
     
    至于这两个函数的使用,给出示范代码(留意自定义代码在调用super的前或后):
    @Override
    public void onSaveInstanceState(Bundle savedInstanceState) {
            savedInstanceState.putBoolean("MyBoolean", true);
            savedInstanceState.putDouble("myDouble", 1.9);
            savedInstanceState.putInt("MyInt", 1);
            savedInstanceState.putString("MyString", "Welcome back to Android");
            // etc.
            super.onSaveInstanceState(savedInstanceState);
    }

    @Override
    public void onRestoreInstanceState(Bundle savedInstanceState) {
            super.onRestoreInstanceState(savedInstanceState);

            boolean myBoolean = savedInstanceState.getBoolean("MyBoolean");
            double myDouble = savedInstanceState.getDouble("myDouble");
            int myInt = savedInstanceState.getInt("MyInt");
            String myString = savedInstanceState.getString("MyString");
    }
     

    2、Service的生命周期

    使用context.startService() 启动Service

    其生命周期为context.startService() ->onCreate()- >onStart()->Service running-->(如果调用context.stopService() )->onDestroy() ->Service shut down

    如果Service还没有运行,则android先调用onCreate()然后调用onStart();
    如果Service已经运行,则只调用onStart(),所以一个Service的onStart方法可能会重复调用多次。 

    调用stopService的时候直接onDestroy,
    如果是调用者自己直接退出而没有调用stopService的话,Service会一直在后台运行。
    该Service的调用者再启动起来后可以通过stopService关闭Service。

    所以调用startService的生命周期为:onCreate --> onStart(可多次调用) --> onDestroy

    对于bindService()启动Service会经历:
    context.bindService()->onCreate()->onBind()->Service running-->onUnbind() -> onDestroy() ->Service stop

    onBind将返回给客户端一个IBind接口实例,IBind允许客户端回调服务的方法,比如得到Service运行的状态或其他操作。
    这个时候把调用者(Context,例如Activity)会和Service绑定在一起,Context退出了,
    Srevice就会调用onUnbind->onDestroy相应退出。 

    所以调用bindService的生命周期为:onCreate --> onBind(只一次,不可多次绑定) --> onUnbind --> onDestory。
    一但销毁activity它就结束,如果按home把它放到后台,那他就不退出。

    PS:

    如何保证服务不被杀死

    1.onStartCommand方法中,返回START_STICKY

    2.提升Service优先级

    3.在onDestory()中发送广播开启自己

    4.可以开启两个服务,相互监听,相互启动。服务A监听B的广播来启动B,服务B监听A的广播来启动A

    startService和bindService混合使用分析


    在Service每一次的开启关闭过程中,只有onStart可被多次调用(通过多次startService调用),
    其他onCreate,onBind,onUnbind,onDestory在一个生命周期中只能被调用一次。

    startService、bindService相信很多人都用过,但一般都只是用其中一种,很少有人会混起来使用。

    最近在开发项目时,遇到这样的需求:在activity中要得到service对象进而能调用对象的方法,但同时又不希望activity finish的时候service也被destory了。

    startService和bindService混合使用就派上用场了。

    首先我们先分析下startService以及bindService后,service的生命周期:

    startService()以后,会执行onCreate()--->onStartCommand()这两个生命周期方法,重复调用startService的话,onStartCommand()也会重复执行。

    stopService()以后,就会执行onDestory()方法。

    大致的生命周期是:onCreate()--->onStartCommand()--->onDestory();

    bindService()以后,会执行onCreate()--->onBind()这两个生命周期方法,重复调用bindService(),onCreate(),onBind()这两个方法不会再执行。

    unbindService()以后,就会执行onUnbind()-->onDestory()方法。

    大致的生命周期是:onCreate()--->onBind()--->onUnbind()-->onDestory();

    那么startService以及bindService混合使用,Service的生命周期会怎么样呢????

    在activity onCreate()中调用startService():

    @Override
    protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_main);
      startService(new Intent(this, TestService.class));
    }

    在activity onStart()中调用bindService():

    @Override
    protected void onStart() {
      super.onStart();
      bindService(new Intent(this, TestService.class), mServiceConnection, Context.BIND_AUTO_CREATE);
    }

    以下是log打印的日志,可以看出Service生命周期:


    如果在activity onCreate()调用bindService(),onStart()方法调用startService(),会出现什么情况呢?看log打印日志

    看起来只是onStartCommand以及onBind的执行顺序换了一个位置而已。

    估计有人会纳闷,这样调用了startService又调用了bindService,他们对应的是同一个service对象吗?

    1.我们先假设不是同一个service对象,那么在startService时,应该会执行onCreate()--->onStartCommand(),而在bindService时,应该会执行onCreate()--->onBind(),

    onCreate()应该会执行两遍才对,但是看日志onCreate()只执行了一遍。

    2.我们再用一个方法来判断是否是同一个service对象,在执行service onStartCommands时把service.this加入到ArrayList中;在执行onBind时,把service.this加入到ArrayList,然后判断两个对象是否是同一个。

    @Override
    public void onCreate() {
      super.onCreate();
      Log.i(CPMainActivity.TAG, "TestService onCreate");
      servicesList.add(this);
    }
     
    @Override
    public IBinder onBind(Intent arg0) {
      servicesList.add(this);
      if(servicesList.get(0)==servicesList.get(1)){
        Log.i(CPMainActivity.TAG, "同一个对象");
      }else{
        Log.i(CPMainActivity.TAG, "不同一个对象");
      }
      return testBinder;
    }

    打印的结果是:

    综合1和2得到的结果是,混合启动方式对应的是同一个对象。

    以上是关于启动的,下面来讨论下退出:

    要实现这样的需求:在activity中要得到service对象调用对象的方法,但同时又不希望activity finish的时候service也被destory了。

    那么在onPause方法中,执行unbindService()即可,只有onUnbind方法会执行,onDestory不会执行(Service依然存在,可通过isDestory方法判断),因为还有一个startService的启动方式存在。

    如果要完全退出Service,那么就得执行unbindService()以及stopService(或者stopSelf)。

    也许有人会问,那如果先执行stopService,会出现什么情况呢?

    答案是:Service依然存在,可通过isDestory方法判断,因为还有一个bindService的启动方式存在。

    无论是先startService后bindService,或者先bindService后startService,得到的结果跟上述的一样。

    这种实现方法的原理就是:只要还有一种启动方法存在,Service就会继续存活。

  • 相关阅读:
    BZOJ2594 [Wc2006]水管局长数据加强版 LCT kruskal
    BZOJ1180 [CROATIAN2009]OTOCI LCT
    BZOJ2631 tree LCT
    BZOJ1901 Zju2112 Dynamic Rankings 主席树
    BZOJ1367 [Baltic2004]sequence 堆 左偏树
    BZOJ5120 [2017国家集训队测试]无限之环 费用流
    BZOJ3377 [Usaco2004 Open]The Cow Lineup 奶牛序列 其他
    BZOJ3091 城市旅行 LCT
    BZOJ2843 极地旅行社 LCT
    BZOJ1269 [AHOI2006]文本编辑器editor splay
  • 原文地址:https://www.cnblogs.com/chenxibobo/p/6136620.html
Copyright © 2011-2022 走看看