0

Android四大组件——Activity——Activity的生命周期 - 虞美人体重90

 2 years ago
source link: https://www.cnblogs.com/Xiang-MY/p/16136553.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

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"   //对键盘隐藏,屏幕大小,屏幕方向都不敏感
当其中一个发生变化时,生命周期不受影响。

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK