• Activity的生命周期


    什么是生命周期呢?

    我们平时在开发软件的时候,就有软件的生命周期。同样的很多事物都有自己的生命周期。一般来说,生命周期不由自己控制。自杀是一个例外,对吧!

    先举个例子吧: – 一辆车的生命周期有:被创建—>被购买—->被使用—–>被报废 – 一个人的生命周期:被成为受精卵—->被出生—–>被长大——>被去世

    Snip20171209_4.png

    相信这两个例子可以理解吧,虽然举得不太好,是吧!!

    而我们的Activity也是有生命周期的:

    被创建—->被开始—>被可视—–>被暂停—–>被停止——>被销毁

    先不用关心实际是怎么回事,把这文章读完你就知道了,实在不行就看视频吧。

    Activity的生命周期

    其实前面我们已经使用到了Activity的生命周期方法了,我们常在onCreate方法里头设置内容呢,找到控件之类的操作。

    Snip20171209_5.png

    这个方法是被系统回调的,也就是不由我们控制的。学习Activity的生命周期有什么用呢?当然有用,我们先举个例子:

    比如说我们前面有这样一个发短信的例子: 它的布局如下:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout
        xmlns:android="https://schemas.android.com/apk/res/android"
        xmlns:tools="https://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        tools:context=".MainActivity">
    
    
        <EditText
            android:id="@+id/message_content"
            android:layout_width="match_parent"
            android:layout_height="100dp"
            android:hint="请输入短信内容!"
            android:inputType="textMultiLine"/>
    
        <Button
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:onClick="sendMsg"
            android:text="发送短信!"/>
    
    </LinearLayout>
    

    Snip20171209_9.png

    Activity里头什么都不写,就这样子:

    package com.sunofbeaches.activitylifecircledemo;
    
    import android.support.v7.app.AppCompatActivity;
    import android.os.Bundle;
    
    public class MainActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
        }
    }
    
    

    接着 ,把应用部署到模拟器上—->再输入一些内容—->点击返回键—–>再打开应用

    Untitled6.gif

    我们很惊讶地发现,我们再次打开这个应用的时候,上次写的东西已经没有了。

    如果想要用户体验好一点,是不是要把数据保存起来呢?那什么时候保存,当然是在销毁之前保存吧。

    那被销毁就是一个生命周期方法啦!

    Snip20171209_10.png

    这个onDetory是怎么回事呢?我们后面再对所有的生命周期方法进行详细的解释。

    我们按前面的想法,我们要在onDetory方法里把数据保存起来,也就是点击返回键的以后保存数据。

    当我们的应用再次跑起来的时候,它又会执行onCreate方法了。这样子就会去sp里拿数据,如果有就回显出来呗!

    如果是忘记了如何保存数据的,请回去看前面有课程吧,这个是网易云的视频地址,免费的哦,欢迎大家给评价哦!

    https://study.163.com/course/introduction/1004334020.htm

    看看后面的效果吧:

    package com.sunofbeaches.activitylifecircledemo;
    
    import android.content.SharedPreferences;
    import android.os.Bundle;
    import android.support.v7.app.AppCompatActivity;
    import android.text.TextUtils;
    import android.widget.EditText;
    
    public class MainActivity extends AppCompatActivity {
    
        private EditText mInputBox;
        private SharedPreferences mMsgConfig;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            //前面我们学习数据存储的时候学习过了sp的存储,这里我们就使用sp来存储这些简单的数据即可
            mMsgConfig = this.getSharedPreferences("MsgConfig", MODE_PRIVATE);
            //输入框控件
            mInputBox = (EditText) this.findViewById(R.id.message_content);
            //在sp里拿到内容
            String content = mMsgConfig.getString("content", null);
            //如果内容不为空的话,再设置到输入框里去,显示出来。
            if (content != null) {
                mInputBox.setText(content);
            }
        }
    
        @Override
        protected void onDestroy() {
            //销毁之前,拿到输入框框的内容,然后判断是否为空,不为空的话保存起来,为下一次进入的时候显示出来。
            String content = mInputBox.getText().toString().trim();
            if (!TextUtils.isEmpty(content)) {
                mMsgConfig.edit().putString("content", content).commit();
            }
            super.onDestroy();
        }
    }
    

    测试结果如下:

    Untitled61.gif

    我们可以发现,当点击返回键退出应用程序的时候数据保存起来了,当我们再次打开应用程序的时候,数据回显了。

    Activity生命周期的微观细聊

    前面我们了解了Activity的两个生命周期方法,分别是onCreate方法和onDestroy方法。

    这两个方法分别会在Activity创建和销毁的时候被调用。

    其实,Activity还有别的生命周期方法,但是我们会重onCreate开始详细学习。

    下面这个是整个的生命周期流程图了,来自官网:

    20171209_152816.png

    onCreate

    onCreate()这个方法是在Activity被创建的时候调用的.在这个方法里头,我们一般做一些初始化的动作,比如说,设置和获取到UI的控件,设置对应的监听事件等。

    我们看看官方文档是怎么说的吧:

    
        /**
         * Called when the activity is starting.  This is where most initialization
         * should go: calling {@link #setContentView(int)} to inflate the
         * activity's UI, using {@link #findViewById} to programmatically interact
         * with widgets in the UI, calling
         * {@link #managedQuery(android.net.Uri , String[], String, String[], String)} to retrieve
         * cursors for data being displayed, etc.
         *
         * <p>You can call {@link #finish} from within this function, in
         * which case onDestroy() will be immediately called without any of the rest
         * of the activity lifecycle ({@link #onStart}, {@link #onResume},
         * {@link #onPause}, etc) executing.
         *
         * <p><em>Derived classes must call through to the super class's
         * implementation of this method.  If they do not, an exception will be
         * thrown.</em></p>
         *
         * @param savedInstanceState If the activity is being re-initialized after
         *     previously being shut down then this Bundle contains the data it most
         *     recently supplied in {@link #onSaveInstanceState}.  <b><i>Note: Otherwise it is null.</i></b>
         *
         * @see #onStart
         * @see #onSaveInstanceState
         * @see #onRestoreInstanceState
         * @see #onPostCreate
         */
    

    能看懂原文的同学看原文,看不懂的看这里吧: onCreate这个方法会在Activity启动的时候被调用。在这个启动的阶段,也就是在这个方法的内部,你可以去做一些初始化的动作。就是前面我们说到的初始话控件,初始化事件之类的。在这个方法里,也应该通过setContentView这个方法来设置Activity加载的UI内容。使用findViewById来找到这个UI里的各控件。

    managedQuery这个先不用学,就算后面学的内容提供都也是很少用到的。这个方法已经过时了,现在用的是CursorLoader这个,大家先不用管这个。我们要知道的是onCreate里面做初始化动作,并且要知道的是,Activity没有被销毁,再次启动的时候是不会被执行的,比如说,我们点击Home键的时候,Activity只是退到后台,并没有销毁掉的。所以,再次启动的时候,是不会调用onCreate方法的。

    如果你在这个方法里头调用finish()方法,那么系统就会直接调用onDestroy()方法了,它会跳过onStart()方 法,会跳过onResume()方法,也会跳过onPause()方法。

    一般来说,我们不会在onCreate方法里调用finish()方法的。大家理解了吗?如果没有理解的话就发帖子讨论吧。

    集成自Activity的类,实现了onCreate方法,必须要调用 super.onCreate(savedInstanceState)这个方法,否则会抛出异常。

    20171209_141857.png

    会报什么异常呢?

    20171209_142021.png

    所以上面的原文说,你要调用 super.onCreate(savedInstanceState);

    接下来我们再看看这个参数:savedInstanceState 这个参数是用来做什么的呢?这里先说一下,这个其实是用来保存数据的。

    一般情况下,这个saveInstanceState为空的,那什么时候它不为空呢?当点击home键的时候,系统就会调用onSaveInstanceState这个方法,你可以在这个方法里保存临时退出时要保存的内容,比如说下载状态呀,当前的进度之类的。

    先看一下例子,理解一下吧:

    package com.sunofbeaches.activitylifecircledemo;
    
    import android.support.v7.app.AppCompatActivity;
    import android.os.Bundle;
    import android.util.Log;
    
    public class MainActivity extends AppCompatActivity {
    
        private static final String TAG = "MainActivity";
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            Log.d(TAG, "onCreate...");
            if (savedInstanceState != null) {
                String saveData = savedInstanceState.getString("saveData");
                Log.d(TAG, "上次系统杀死时保存的内容... " + saveData);
            }
        }
    
        @Override
        protected void onSaveInstanceState(Bundle outState) {
            super.onSaveInstanceState(outState);
            Log.d(TAG, "onSaveInstanceState...");
            outState.putString("saveData", "我是保存的数据");
        }
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
            Log.d(TAG, "onDestroy...");
        }
    }
    
    

    然后进行以下的操作:

    启动这个应用,我们可以看到执行了onCreate方法,接着,点击home键,就发会现执行onSaveInstanceState这个方法,在这个方法里头,我们保存了一条数据。接着,我们模拟系统杀死这个应用,我们打开DDMS,直接选择当前的进程,然后stop掉,再次启动我们的应用时,就会发现,onCreate方法的时候 ,这个savedInstanceState就不为空了。并且保存着上次的数据,我们读出来。

    20171209_151225.png

    这个onSaveInstanceState方法什么时候会执行呢?系统把你退到后台的时候会执行。 比如说:点击了home键盘;长按home键选择其他应用的时候,也就是切换应用;从当前的Activity启动到新的Activity里也会被调用;横竖屏的切换也会被调用,这里的话仅作理解,初学者暂时不需要深入学习。后面实际开发的时候,我们讲项目的时候,我们就会进行讲解了。什么场景下使用到。

    好啦,我们onCreate方法先讲这么多吧。

    要知道这个是生命周期方法,并且知道在这个方法里面做什么就可以了,还要注意的是onCreate要调用super的方法,否则会崩溃。这个的话不用担心,IDE在创建Activity的时候,你复写onCreate方法,直接会帮你写上的。

    onStart

    onStart方法的官方文档是这么写的:

      /**
         * Called after {@link #onCreate} — or after {@link #onRestart} when
         * the activity had been stopped, but is now again being displayed to the
         * user.  It will be followed by {@link #onResume}.
         *
         * <p><em>Derived classes must call through to the super class's
         * implementation of this method.  If they do not, an exception will be
         * thrown.</em></p>
         *
         * @see #onCreate
         * @see #onStop
         * @see #onResume
         */
    

    这个方法会在onCreate方法以后调用,或者会在onRestart这个方法调用以后被调用,看到这里,返回去看看前面的Activity声明周期流程图吧:

    20171209_153108.png

    同样的,也要和onCreate方法一样,需要调用super方法哦。这个方法一般比较少用到。大家后面看视频的时候留意一下就可以了。

    onResume

    到了onResume方法,官方原文:

       /**
         * Called after {@link #onRestoreInstanceState}, {@link #onRestart}, or
         * {@link #onPause}, for your activity to start interacting with the user.
         * This is a good place to begin animations, open exclusive-access devices
         * (such as the camera), etc.
         *
         * <p>Keep in mind that onResume is not the best indicator that your activity
         * is visible to the user; a system window such as the keyguard may be in
         * front.  Use {@link #onWindowFocusChanged} to know for certain that your
         * activity is visible to the user (for example, to resume a game).
         *
         * <p><em>Derived classes must call through to the super class's
         * implementation of this method.  If they do not, an exception will be
         * thrown.</em></p>
         *
         * @see #onRestoreInstanceState
         * @see #onRestart
         * @see #onPostResume
         * @see #onPause
         */
    

    看前面的流程图,我们可以知道,这个方法会在onRestoreInstanceState方法或者onRestart方法或者onPause这个方法以后被调用。这个方法以后就可以和用户进行交互了。在这个方法里面开始动画是不错的做法,打开相机等等操作…可是我没有做过,哈哈!!!只是翻译原文。

    这个方法在实际开发中,用得最多的是什么情况呢?

    就是可见的时候,需要做一些动画,比如说,我以前在做手表的时候,有这样一个效果:

    adjustNumber1.gif

    直接创建不算典型的,典型的是onResume跟onCreate方法有一个区别,onCreate方法如果不销毁掉是不会再执行的,但是onResume,你退到了后台以后,再回来就会执行这个方法了。

    要注意的是在onResume这个方法并不一定保证当前Activity在前台的,比如说键盘已经显示出来了。这个时候,当前Activity是失去焦点的,所以,可以使用onWindowFocusChanged这个方法来判断当前Activity是否可见。

    同样的,这个方法也要调用super,否则还是会崩溃掉的。

    onPause

    onPause这个方法是暂停的意思是吧,暂停,什么时候会调用呢?失去焦点了

    fter the next activity has been resumed and
         * displayed), however in some cases there will be a direct call back to
         * {@link #onResume} without going through the stopped state.
         *
         * <p><em>Derived classes must call through to the super class's
         * implementation of this method.  If they do not, an exception will be
         * thrown.</em></p>
         *
         * @see #onResume
         * @see #onSaveInstanceState
         * @see #onStop
         */
    

    这个方法也是声明周期方法,它会在当前Activity进入后台但又没被杀死的时候会被调用。它对应着onResume,其实我们的声明周期一般来说是对应着的。 比如说:

    onStart—-onStop onResume—onPause onCreate—-onDestroy

    理解了吗?

    在这个方法里不要做耗时操作,假设说,你要打开另外一个Activity,真到这个方法的onPause方法返回了,才会去启动另外一个Activity。

    在这个方法里头,一般保存正在编辑的数据,除了保存数据以外,还可以停止动画,因为它是跟onResume对应的嘛。在onResume开始动画,我们要是还有一些在循环播放的动画,我们可以在这个方法里头暂停掉它。在这个方法里头释放资源也是可以的,释放掉资源可以更快地启动到下一个界面。

    某些情况下系统可能会回收资源。所以有些东西你需要在这个地方进行保存。通常来说,如果是系统干的坏事,它会调用onSaveInstanceState这个方法的,在这个方法里头保存就好,前面我们已经讲过了。

    这个方法被调用以后,当被启动的Activity可见的时候,接下来就会调用onStop方法了。但是有些情况下直接调用新的Activity的onResume方法,不会调用当前Activity的onStop方法.

    这个方法也要调用super的方法,否则也会崩溃掉。

    onStop

    停止的回调,这个方法一般是执行完onPause,要退出了,则会调用。假设说,顶部有一个透明的Activity,则不会调用当前的onStop方法,但会调用到onPause方法。

     /**
         * Called when you are no longer visible to the user.  You will next
         * receive either {@link #onRestart}, {@link #onDestroy}, or nothing,
         * depending on later user activity.
         *
         * <p>Note that this method may never be called, in low memory situations
         * where the system does not have enough memory to keep your activity's
         * process running after its {@link #onPause} method is called.
         *
         * <p><em>Derived classes must call through to the super class's
         * implementation of this method.  If they do not, an exception will be
         * thrown.</em></p>
         *
         * @see #onRestart
         * @see #onResume
         * @see #onSaveInstanceState
         * @see #onDestroy
         */
    

    onStop方法会在你再也看不到当前Activity的时候调用,当上面的Activity是透明你的时候,那么是不会调用的,这个是考点哦。

    这个方法以有两个可能,要么被onRestart,要么就被调用onDestroy,或者啥也不干,这取决于后面的操作。有些情况下这个方法可能不会被执行。比如说系统的内存不足以来跑当前的Activity的时候,调用了onPause就不调用onStop方法了,所以在这个方法里头不要做一些保存数据的东西,可能不安全,没有保障.

    onDestroy

    onDestroy这个方法,我们早在前面就已经用了是吧,我们保存内容,并且在onCreate的方法我们回显数据。

     /**
         * Perform any final cleanup before an activity is destroyed.  This can
         * happen either because the activity is finishing (someone called
         * {@link #finish} on it, or because the system is temporarily destroying
         * this instance of the activity to save space.  You can distinguish
         * between these two scenarios with the {@link #isFinishing} method.
         *
         * <p><em>Note: do not count on this method being called as a place for
         * saving data! For example, if an activity is editing data in a content
         * provider, those edits should be committed in either {@link #onPause} or
         * {@link #onSaveInstanceState}, not here.</em> This method is usually implemented to
         * free resources like threads that are associated with an activity, so
         * that a destroyed activity does not leave such things around while the
         * rest of its application is still running.  There are situations where
         * the system will simply kill the activity's hosting process without
         * calling this method (or any others) in it, so it should not be used to
         * do things that are intended to remain around after the process goes
         * away.
         *
         * <p><em>Derived classes must call through to the super class's
         * implementation of this method.  If they do not, an exception will be
         * thrown.</em></p>
         *
         * @see #onPause
         * @see #onStop
         * @see #finish
         * @see #isFinishing
         */
    

    在这个方法里做释放资源的动作,比如说,取消一些广播的注册,解绑服务。不要在这个方法里保存数据哦,前面那个例子是为了给大家演示。在onPause方法保存数据或者在onSaveInstanceState方法里保存数据。就是不要在这里保存数据就好。这个方法通常用于释放资源,比如说释放线程,释放掉的话就不会泄露了。有些情况下不会调用这个方法,所以这里不要使用一直在跑的进程。

    这个方法也要调用super的方法,否则的话会崩溃掉的。

    onPause和onStop

    我们前面详细地翻译和解释了每个生命周期的特点,不管是同学们在看视频,还是看文章自己做实验。我们会发现当我们点击Home键的时候,生命周期会执行–>onPause—>onStop。

    前面我们也提到了,onPause是失去焦点的意思,对应着onResume获得焦点。

    onStop是不可见了,所以。我们的Activity先是失去焦点,再是不可见!于是就有了这样的生命周期:onPause–>onStop

    但是,面试的时候可能会有一种特殊的情况:我们的当前Activity,去启动另外一个透明的Activity时,当前的Activity生命周期变化是怎么样的?

    答案是:onPause,没有onStop。因为是透明的,所以前一个Activity还是可见的。只是失去焦点而已,并不是不可见!

    验证代码如下:

    先是第一个Activity:

    package com.sunofbeaches.activitylifecircledemo;
    
    import android.app.Activity;
    import android.content.Intent;
    import android.os.Bundle;
    import android.util.Log;
    import android.view.View;
    
    /**
     * Created by TrillGates on 17/12/12.
     * God bless my code!
     */
    public class FirstActivity extends Activity {
        private static final String TAG = "FirstActivity";
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_first);
            Log.d(TAG, "onCreate....");
        }
    
        public void skip2SecondActivity(View view) {
            Intent intent = new Intent(this, SecondActivity.class);
            startActivity(intent);
        }
    
        @Override
        protected void onStart() {
            super.onStart();
            Log.d(TAG, "onStart....");
        }
    
        @Override
        protected void onResume() {
            super.onResume();
            Log.d(TAG, "onResume....");
        }
    
        @Override
        protected void onPause() {
            super.onPause();
            Log.d(TAG, "onPause....");
        }
    
        @Override
        protected void onStop() {
            super.onStop();
            Log.d(TAG, "onStop....");
        }
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
            Log.d(TAG, "onDestroy....");
        }
    }
    
    

    第一个Activity的布局很简单:

    Snip20171212_15.png

    第二个Activity的代码,其实什么都没有写:

    package com.sunofbeaches.activitylifecircledemo;
    
    import android.app.Activity;
    import android.os.Bundle;
    
    /**
     * Created by TrillGates on 17/12/12.
     * God bless my code!
     */
    public class SecondActivity extends Activity {
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_second);
        }
    }
    
    

    界面:

    Snip20171214_17.png

    我们设置一下第二个样式为透明:

    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="https://schemas.android.com/apk/res/android"
              package="com.sunofbeaches.activitylifecircledemo">
    
        <application
            android:allowBackup="true"
            android:icon="@mipmap/ic_launcher"
            android:label="@string/app_name"
            android:supportsRtl="true"
            android:theme="@style/AppTheme">
            <activity android:name=".MainActivity">
    
            </activity>
            <activity android:name=".FirstActivity">
                <intent-filter>
                    <action android:name="android.intent.action.MAIN"/>
    
                    <category android:name="android.intent.category.LAUNCHER"/>
                </intent-filter>
            </activity>
            <activity
                android:name=".SecondActivity"
                android:theme="@android:style/Theme.Translucent"></activity>
        </application>
    
    </manifest>
    

    当我们把应用跑起来,点击跳转到第二个界面,我们看生命周期的变化。

    Snip20171214_18.png

    当我们把应用跑起来,点击跳转到第二个界面,我们看生命周期的变化。

    Activity生命周期的分类

    完整的声明周期:

    也就是说,从onCreate开始,一直到onDestroy方法执行完成。这就是一个完整的声明周期。 一般来说,完整的声明周期走完所有的声明周期方法。在onCreate方法的时候初始化资源,在onDestroy方法释放资源。

    Activity可见的声明周期:

    可见的声明周期就是调用onStart到调用onStop这段声明周期。在这其间,用户可以看到UI,也可以进行交互。在这两个方法之间,你可以让要显示的数据显示给用户。栗子我就不说了。

    前台生命周期:

    什么是前台呢?也就是正在操作的,相对于后台运行来说的。前台生命周期是从onResume到onPause这期间。在这期间的话,Activity会跑在前台。Activity可能会频繁地切换于onResume和onPause这两个方法间。前面我们讲到了,onResume是获取到了焦点了,onPause就失去焦点了。

    原文的内容如下:

    20171213_165921.png

    Activity的生命周期宏观概括

    声明周期就像人的各个阶段,但是有些阶段不是每个人都经历的,而重点是在对应的阶段做对应的事情。这就是总结啦!

    实际的使用,还得从实际开发中去体会,这节课了解一下先,在以后的工作中就慢慢地理解了。但是呢,这样子还不够的,因为出来工作的时候,面试可能会遇到哦。

  • 相关阅读:
    「BZOJ4763」雪辉
    「CSA72」MST
    「CSA49」Bunny on Number Line
    「CSA49」Card Collecting Game
    Java indexOf() 方法
    MySQL执行计划分析
    NIO编程
    数据结构可视化
    深入理解二阶段提交协议(DDB对XA悬挂事务的处理分析)(一)
    linux下nohup日志切割方案
  • 原文地址:https://www.cnblogs.com/wcyMiracle/p/13380043.html
Copyright © 2020-2023  润新知