• Android四大组件——Activity——Activity的生命周期


    Activity状态:

    每个Activity在其生命周期中最多可能有四种状态

    1.运行状态:处于栈顶时。初次创建处于栈顶时依次调用:onCreate(),onStart(),onResume()。由不可见重新处于栈顶时依次调用:onRestart(),onStart(),onResume()。由可见重新处于栈顶时调用:onResume()

    2.暂停状态:可见却不在栈顶。例如在MainActivity中启动一个对话框式Activity时。该对话框式Activity处于栈顶,但MainActivity仍然可见,只是MainActivity不处于栈顶。调用onPause()。如下图:

    3.停止状态:不可见并且不在栈顶时。例如在MainActivity中启动一个普通的Activity时,该Activity会彻底覆盖MainActivity,致使MainActivity不可见,这时MainActivity便进入了停止状态。依次调用onPause(),onStop()

    4.销毁状态:从栈中移除后。例如在MainActivity界面按下返回键,这时是将MainActivity从栈顶移除,这样被移除后的MainActivity就成了销毁状态。依次调用onPause(),onStop(), onDestroy()

     

     

     onCreate():该方法会在Activity第一次被创建的时候调用。我们一般都会重写此方法,完成一些Activity的初始化操作,如加载布局,绑定事件等。该方法使得Activity创建。

     onStart():该方法在Activity由不可见变为可见时调用。使得Activity可见。

     onResume():该方法在Activity准备好和用户进行交互时调用。此时的Activity一定返回栈的栈顶,并且处于运行状态。使得Activity获取焦点,可以进行操作(交互)

     onPause():该方法在系统准备去启动或者恢复另一个Activity的时候调用,我们通常会在这个方法中将一些消耗CPU的资源释放掉,以及保存一些关键数据,但这个方法的执行速度一定要快,不然会影响到新的栈顶Activity的使用。使得Activity失去焦点,不能交互。

     onStop():该方法在Activity完全不可见的时候调用。它和onPause()方法的主要区别在于,如果启动一个新的Activity是一个对话框式的Activity,那么onPause()方法会得到新的执行,而onStop()方法并不会执行。使得Activity不可见

     onDestroy():该方法在Activity被销毁之前调用,之后Activity的状态将变为销毁状态。使得Activity销毁。

     onRestart():该方法在Activity由停止状态变为运行状态之前调用。也就是Activity被重新启动了。

    1.创建三个Activity:MainActivity , AActivity(普通的Activity) , BActivity(对话框式Activity)

    怎么将 BActivity设成对话框式?在AndroidManifest.xml中的<.activity>标签中

            <activity android:name=".BActivity"
                      android:theme="@style/Theme.AppCompat.Dialog">
            </activity>

    通过android:theme="@style/Theme.AppCompat.Dialog"指定当前Activity主题为对话框式。

    2.修改MainActivity的代码:

    复制代码
    package com.java.androidstudy;
    
    import androidx.appcompat.app.AppCompatActivity;
    import android.content.Intent;
    import android.os.Bundle;
    import android.util.Log;
    import android.view.View;
    import android.widget.Button;
    
    public class MainActivity extends AppCompatActivity {
        private Button normal_btn;
        private Button dialog_btn;
        private String tag = "MainActivity";
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            Log.d(tag,"onCreate");
            setContentView(R.layout.activity_main);
            initView();
            normal_btn.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Intent intent = new Intent(MainActivity.this,AActivity.class);
                    startActivity(intent);
                }
            });
    
            dialog_btn.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Intent intent = new Intent(MainActivity.this,BActivity.class);
                    startActivity(intent);
                }
            });
        }
    
        private void initView(){
            normal_btn = findViewById(R.id.a_btn);
            dialog_btn = findViewById(R.id.b_btn);
        }
    
        @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()");
        }
    
        @Override
        protected void onRestart() {
            super.onRestart();
            Log.d(tag,"onRestart()");
        }
    
    }
    复制代码

    点击运行后,如下图:

     

     

     此刻观看日志:

     

     

     可以发现当MainActivity第一次被创建时会依次执行onCreate(),onStart(),onResume()

     

    点击第一个按钮:启动普通的Activity,这时会启动AActivity,该AActivity入栈,位于栈顶,会将MainActivity完全遮挡住,因此onPause() 和 onStop()都会得到执行。

     

     

     查看日志:

     

     

     依次执行了onPause() 和 onStop()

     

    点击退出

    之前被遮挡住的MainActivity此时处于停止状态,点击退出时,AActivity出栈,MainActivity重新处于栈顶,由停止状态变为运行时状态。所以先调用onRestart(),之后会依次执行onStart()和onResume()。注意,此时onCreate()方法不会执行,因为MainActivity没有重新创建。

     

     

     

     

    点击第二个按钮:启动对话框式Activity。如下图:

    观察日志:

     

     

      此时只执行了onPause(),没有执行onStop()方法。这是因为对话框式的BActivity并没有完全遮挡住MainActivity,此时的MainActivity只是进入了暂停状态。(之前启动AActivity时,MainActivity进入了停止状态。),相应的,按下返回键,也只有onResume()方法会得到执行。如下:

     

     

    最后在MainActivity界面按下返回键,此时日志信息如下:

     

    依次执行onPause(),onStop(),onDestroy().销毁MainActivity.

     

     

    具体实践:

    1.onCreate()和onDestory()的使用

    onCreate():第一次创建Activity的时候调用

    onDestory():销毁Activity的时候调用

      修改MainActivity的布局:添加两个输入。

     现在的输入框,若是我输入到一半,突然退出,再次进入就要重新输入。但是我不想那么麻烦,我希望输入框能自动显示上次退出前的内容。

    分析:在Activity销毁前将输入框中的内容保存,再次启动Activity时将保存的内容显示到输入框。(l类似于记住密码功能)

    Activity销毁前保存数据:需要在onDestroy()中操作

    Activity再次启动时显示数据:需要在onCreate中操作

     

    代码如下:

    复制代码
    package com.java.androidstudy;
    
    import androidx.appcompat.app.AppCompatActivity;
    import android.content.Intent;
    import android.content.SharedPreferences;
    import android.os.Bundle;
    import android.util.Log;
    import android.view.View;
    import android.widget.Button;
    import android.widget.EditText;
    
    public class MainActivity extends AppCompatActivity {
        private Button normal_btn;
        private Button dialog_btn;
        private String tag = "MainActivity";
        private EditText user;
        private EditText password;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            Log.d(tag,"onCreate");
            setContentView(R.layout.activity_main);
            initView();
            displayinfo();
    
        }
    
        private void initView(){
            normal_btn = findViewById(R.id.a_btn);
            dialog_btn = findViewById(R.id.b_btn);
            user = findViewById(R.id.user);
            password = findViewById(R.id.password);
        }
    
        private void displayinfo(){
            String content_user = getSharedPreferences("myinfo",0).getString("user","");
            String content_pwd = getSharedPreferences("myinfo",0).getString("pwd","");
            user.setText(content_user);
            password.setText(content_pwd);
        }
    
        @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()");
            //获取输入的内容
            String content_user = user.getText().toString();
            String content_password = password.getText().toString();
    
            //使用SharedPerences存储数据
            SharedPreferences.Editor editor = getSharedPreferences("myinfo",0).edit();
            editor.putString("user",content_user);
            editor.putString("pwd",content_password);
            editor.apply();
        }
    
        @Override
        protected void onRestart() {
            super.onRestart();
            Log.d(tag,"onRestart()");
        }
    
    }
    复制代码

     运行效果如下:

     

     会自动将上次退出时的内容显示出来。

    2.onStart()和onStop的使用

    onStart():此时可见,没有焦点,也就是不可以进行操作

    onStop():此时不可见。没有焦点

     

    复制代码
    package com.java.androidstudy;
    
    import androidx.appcompat.app.AppCompatActivity;
    
    import android.os.Bundle;
    import android.util.Log;
    import android.view.View;
    import android.widget.Button;
    import android.widget.TextView;
    /*
    有这样一个需求:当正在看电影的时候,突然打来电话,如果接听电话,而电影也在播放,杂音十分影响使用感。
            现在需要接听电话时电影自动暂停,挂断电话后电影继续播放。 分析:接电话时会依次执行onPause()和onStop()方法,所以我们可以在onStop()方法中暂停电影 挂断电话回答该界面时会依次执行onRestart(),onStart(),onResume。我们可以在onStart()中继续播放电影
    */ public class AActivity extends AppCompatActivity { private static final String TGA = "AActivity"; private TextView play; private Button play_control; private boolean isPlay = false; private boolean isStopAtAmin = false;//是否是因为生命周期的变化而主动停止的 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_a); Log.d(TGA,"onCreate"); initView(); initListener(); } private void initView() { play = findViewById(R.id.play); play_control = findViewById(R.id.play_control); } private void initListener(){ play_control.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if(isPlay){//如果当前状态是播放的,点击该按钮后就暂停播放,并将按钮上的文字显示为播放 stop(); }else { //如果当前状态是暂停的,点击该按钮后变为播放状态,并将按钮上的文字显示为暂停 play(); } } }); } private void stop() { Log.d(TGA,"暂停电影"); play.setText("电影已经暂停!!!"); play_control.setText("播放"); isPlay = false; } private void play() { Log.d(TGA,"播放电影"); play.setText("正在播放电影!!!"); play_control.setText("暂停"); isPlay = true; } @Override protected void onStart() { super.onStart(); Log.d(TGA,"onStart()"); if (isStopAtAmin){ //如果是因为生命周期结束停止的,在重新回到栈顶时播放电影 play(); isStopAtAmin = false; } } @Override protected void onStop() { super.onStop(); Log.d(TGA,"onStop() "); if (isPlay){//如果当前是播放的,那么我们需要将这个电影停掉。 stop(); isStopAtAmin = true; } } @Override protected void onResume() { super.onResume(); Log.d(TGA,"onResume()"); } @Override protected void onPause() { super.onPause(); Log.d(TGA,"onPause()"); } @Override protected void onRestart() { super.onRestart(); Log.d(TGA,"onRestart()"); } @Override protected void onDestroy() { super.onDestroy(); Log.d(TGA,"onDestroy()"); } }
    复制代码

     

    运行如下:

     

     点击播放电影:

     

     此刻接听电话:右下图,可以发现依次执行了onPause(),onStop()。然后暂停电影

     

     此刻挂断电话:可以看到依次执行了onRestart()onStart(),onResume()。并在start()方法中自动播放电影。

     

     3.onResume() 和 onPause()

    onResume():onstart()可见之后在这里获取到焦点,可以进行操作。

    onPause():失去焦点,不可以操作。

    当从FirstActivity跳转到SecondActivity后,SecondActivity至于栈顶处于可见状态,而FirstActivity进入停止状态(如果SecondActivity是对话框式的Activity,则FirstActivity进入暂停状态),在SecondActivity界面点击返回键后,SecondActivity出栈(销毁),这时FirstActivity重新处于栈顶,执行onRestart()方法,再依次执行 onStart(),onResume()。

    注意:这里不止对话框式Activity(透明主题也可以),只要FirstActivity仍然可见,就不会执行onStop()方法使之进入停止状态(该状态不可见),而是只执行onPasue()方法使之进入暂定状态(该状态失去焦点,不可点击)

    代码:

     

    复制代码
    package com.java.androidstudy;
    
    import androidx.appcompat.app.AppCompatActivity;
    
    import android.content.Intent;
    import android.os.Bundle;
    import android.util.Log;
    import android.view.View;
    import android.widget.Button;
    
    public class FirstActivity extends AppCompatActivity {
        private static final String TGA = "FirstActivity";
        private  Button btn_first;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_b);
            Log.d(TGA,"onCreate");
            initView();
            initListener();
        }
    
        private void initListener() {
            btn_first.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Intent intent = new Intent(FirstActivity.this,SecondActivity.class);
                    startActivity(intent);
                }
            });
        }
    
        private void initView() {
            btn_first = findViewById(R.id.btn_first);
        }
    
        @Override
        protected void onStart() {
            super.onStart();
            Log.d(TGA,"onStart()");
        }
    
        @Override
        protected void onStop() {
            super.onStop();
            Log.d(TGA,"onStop() ");
        }
    
        @Override
        protected void onResume() {
            super.onResume();
            Log.d(TGA,"onResume()");
        }
    
        @Override
        protected void onPause() {
            super.onPause();
            Log.d(TGA,"onPause()");
        }
    
        @Override
        protected void onRestart() {
            super.onRestart();
            Log.d(TGA,"onRestart()");
        }
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
            Log.d(TGA,"onDestroy()");
        }
    }
    复制代码

     

    然后将SecondActivity的主题改成透明主题:

            <activity android:name=".SecondActivity"
                android:theme="@android:style/Theme.Translucent">
            </activity>

    运行效果:

     

     点击按钮后:

     

     可以看到第二个页面弹出来了,但是第一个页面仍然可见,只是失去了焦点,不能点击。

    看看日志:

     FirstActivity只是进入了暂停状态,失去焦点。

    点击返回键,使得SecondActivity销毁。查看日志:

    这时FirstActivity重新进入栈顶,获取焦点。

     

    横竖屏切换Activity生命周期的变化

     MainActivity:

    复制代码
    package com.java.androidstudy;
    
    import androidx.appcompat.app.AppCompatActivity;
    import android.os.Bundle;
    import android.util.Log;
    
    
    public class MainActivity extends AppCompatActivity {
        private String tag = "MainActivity";
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            Log.d(tag,"onCreate");
            setContentView(R.layout.activity_main);
        }
    
        @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()");
        }
    
        @Override
        protected void onRestart() {
            super.onRestart();
            Log.d(tag,"onRestart()");
        }
    
    }
    复制代码

    运行后:

     

     查看日志:

    现在旋转成横屏:

     

     再来看看完整的生命周期变化:

     

     红框内的为横屏后的变化。

    可以看到:在点击横屏后,是先将原Activity销魂,再创建新的Activity

    再将其从横屏切换为竖屏:

     

     与竖屏切换横屏一样,都会先销毁Activity再重新创建。

     

    横竖屏切换的问题:

    如:将看到一半的电影切换成横屏,因为切换后是创建新的Activity,所以会造成进度条清零,需要手动去拉进度条,这种体验无疑是极差的

    如:

    复制代码
    package com.java.androidstudy;
    
    import androidx.appcompat.app.AppCompatActivity;
    import android.os.Bundle;
    import android.util.Log;
    import android.widget.SeekBar;
    
    
    public class MainActivity extends AppCompatActivity {
        private String tag = "MainActivity";
        private SeekBar progress;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            Log.d(tag,"onCreate");
            setContentView(R.layout.activity_main);
            initView();
    
        }
    
        private void initView() {
            progress = findViewById(R.id.progress);
            progress.setMax(100);
            progress.post(new Runnable() {
                @Override
                public void run() {
                    progress.setProgress(0); //每次初始化的时候进度条清零
                }
            });
        }
    
        @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()");
        }
    
        @Override
        protected void onRestart() {
            super.onRestart();
            Log.d(tag,"onRestart()");
        }
    
    }
    复制代码

     

    切换前:

     

     此时进度条到一半。

    切换成横屏:

     

     可以看见进度条自动清零了。

     

    怎么解决:

    第一种:禁止屏幕旋转,指定屏幕方向。(适合只有一种屏幕状态的应用开发配置)

    复制代码
            <activity android:name=".MainActivity"
                android:screenOrientation="landscape">
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
    复制代码
     android:screenOrientation="landscape"  //指定为横屏
     android:screenOrientation="portrait"   //指定为竖屏

    这样指定后的横竖屏切换不会销毁原来的Activity再创建新的Activity。

    第二种:设置配置信息改变不影响。(适合有两种/多种屏幕状态的应用开发,如:视频播放器)
    复制代码
            <activity android:name=".MainActivity"
                android:configChanges="keyboardHidden|screenSize|orientation">
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
    复制代码
     android:configChanges="keyboardHidden|screenSize|orientation"   //对键盘隐藏,屏幕大小,屏幕方向都不敏感
    当其中一个发生变化时,生命周期不受影响。
  • 相关阅读:
    Vue3表单页面利用keep-alive缓存数据的一种思路
    Mybatis-Plus报错:can not use this method for “getSqlSet“ | 带你从源码层面解析异常
    Android实战——一步一步实现流动的炫彩边框
    【AI】用iOS的ML(机器学习)创建自己的AI App
    el7升级Apache模块编译
    【C语言进阶】---- 自定义类型详解
    【Proteus】:LCD1602仿真实验基于STM32CubeMX
    搜索技术【广度优先搜索】 - 嵌套广度优先搜索 【POJ No. 1475】 推箱子 Pushing Boxes
    RpcProvider分发rpc服务:socket连接回调和读写事件回调的实现
    华为OD机试 - 敏感字段加密(Java 2023 B卷 100分)
  • 原文地址:https://www.cnblogs.com/Xiang-MY/p/16136553.html