>  기사  >  Java  >  Android 기본 활동 수명 주기

Android 기본 활동 수명 주기

高洛峰
高洛峰원래의
2017-01-07 15:34:551282검색

기술 학습도 마찬가지다. 기술 문서나 고전 기술 서적은 기본적으로 한 번 읽고 완전히 파악하는 것이 불가능하기 때문에 저자의 생각을 이해하기 위해서는 자주 돌아가서 주의 깊게 읽어야 한다. 본질.

최근에 액티비티의 라이프 사이클을 검토했는데, 이전에 이해했던 내용이 많이 향상되었습니다.

javaEE에 익숙한 친구들은 모두 서블릿 기술을 알고 있습니다. 자체 서블릿을 구현하려면 해당 기본 클래스를 상속하고 해당 메소드를 다시 작성해야 합니다. 이 메소드는 서블릿 컨테이너에서 호출됩니다. 적절한 시간에. 실제로 Android의 Activity 실행 메커니즘은 서블릿과 다소 유사합니다. Android 시스템은 서블릿 컨테이너와 동일하며 Activity는 이 컨테이너에 있으며 인스턴스 생성, 초기화, 인스턴스 파괴는 컨테이너에 의해 수행됩니다. 이는 소위 "전화하지 마세요. 전화하겠습니다."입니다.

이 고전적인 수명주기 흐름도를 살펴보겠습니다.

Android 기본 활동 수명 주기

많은 친구들이 이미 이 흐름도를 본 적이 있을 것입니다. 기본적으로 이제 우리는 활동 수명주기의 여러 프로세스를 이해했습니다. 이러한 프로세스에 대해 이야기해 보겠습니다.

1. 액티비티 시작: 시스템은 먼저 onCreate 메서드를 호출한 다음 onStart 메서드를 호출하고 마지막으로 onResume을 호출하면 액티비티가 실행 상태로 들어갑니다.

2. 현재 활동을 다른 활동으로 덮어쓰거나 화면이 잠긴 경우: 시스템은 onPause 메서드를 호출하여 현재 활동의 실행을 일시 중지합니다.

3. 현재 액티비티가 포그라운드로 돌아가거나 가려진 상태에서 화면 잠금을 해제합니다. 시스템은 onResume 메서드를 호출하고 다시 실행 상태로 들어갑니다.

4. 현재 활동은 새로운 활동 인터페이스로 전환되거나 홈 버튼을 눌러 홈 화면으로 돌아가고 배경으로 돌아갑니다. 시스템은 먼저 onPause 메서드를 호출한 다음 onStop 메서드를 호출합니다. 정체상태에 들어갑니다.

5. 사용자가 이 활동으로 돌아갑니다. 시스템은 먼저 onRestart 메서드를 호출한 다음 onStart 메서드를 호출하고 마지막으로 onResume 메서드를 호출하여 다시 실행 상태로 들어갑니다.

6. 현재 활동이 백그라운드에서 덮어쓰여지거나 보이지 않습니다. 즉, 2단계와 4단계에서 시스템의 메모리가 부족하여 현재 활동이 종료됩니다. 그런 다음 사용자는 현재 활동으로 돌아갑니다. onCreate 메소드와 onStart 메소드, onResume 메소드를 다시 실행 상태로 들어갑니다.

7. 사용자가 현재 활동을 종료합니다. 시스템은 먼저 onPause 메서드를 호출한 다음 onStop 메서드를 호출하고 마지막으로 onDestory 메서드를 호출하여 현재 활동을 종료합니다.

그러나 이것을 아는 것만으로는 충분하지 않습니다. 우리는 그것을 깊이 이해하고 이해하기 위해 노력해야 합니다.

아래에서는 예제를 사용하여 수명 주기의 여러 프로세스에 대한 세부 정보를 보여줍니다.

1. onWindowFocusChanged 메서드: 현재 활동이 다른 활동에 의해 생성될 때 사용자에게 처음 표시될 때와 같이 활동 창이 포커스를 얻거나 잃을 때 호출됩니다. 다른 활동으로 이동하거나 홈 버튼을 눌러 홈 화면으로 돌아가고 사용자가 현재 활동을 종료합니다. 위의 상황에서 OnWindowFocusChanged가 호출되며, Activity가 생성되면 onResume 이후에 호출됩니다. Activity가 백그라운드로 덮어쓰이거나 후퇴되거나 현재 Activity가 종료되면 그림과 같이 onPause 이후에 호출됩니다.

package com.scott.lifecycle;
 
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
 
public class LifeCycleActivity extends Activity {
     
    private static final String TAG = "LifeCycleActivity";
    private Context context = this;
    private int param = 1;
     
    //Activity创建时被调用
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    Log.i(TAG, "onCreate called.");
     
    setContentView(R.layout.lifecycle);
     
    Button btn = (Button) findViewById(R.id.btn);
    btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(context, TargetActivity.class);
                startActivity(intent);
            }
        });
  }
   
  //Activity创建或者从后台重新回到前台时被调用
  @Override
  protected void onStart() {
    super.onStart();
    Log.i(TAG, "onStart called.");
  }
   
  //Activity从后台重新回到前台时被调用
  @Override
  protected void onRestart() {
    super.onRestart();
    Log.i(TAG, "onRestart called.");
  }
   
  //Activity创建或者从被覆盖、后台重新回到前台时被调用
  @Override
  protected void onResume() {
    super.onResume();
    Log.i(TAG, "onResume called.");
  }
   
  //Activity窗口获得或失去焦点时被调用,在onResume之后或onPause之后
  /*@Override
  public void onWindowFocusChanged(boolean hasFocus) {
    super.onWindowFocusChanged(hasFocus);
    Log.i(TAG, "onWindowFocusChanged called.");
  }*/
   
  //Activity被覆盖到下面或者锁屏时被调用
  @Override
  protected void onPause() {
    super.onPause();
    Log.i(TAG, "onPause called.");
    //有可能在执行完onPause或onStop后,系统资源紧张将Activity杀死,所以有必要在此保存持久数据
  }
   
  //退出当前Activity或者跳转到新Activity时被调用
  @Override
  protected void onStop() {
    super.onStop();
    Log.i(TAG, "onStop called.");   
  }
   
  //退出当前Activity时被调用,调用之后Activity就结束了
  @Override
  protected void onDestroy() {
    super.onDestroy();
    Log.i(TAG, "onDestory called.");
  }
   
  /**
   * Activity被系统杀死时被调用.
   * 例如:屏幕方向改变时,Activity被销毁再重建;当前Activity处于后台,系统资源紧张将其杀死.
   * 另外,当跳转到其他Activity或者按Home键回到主屏时该方法也会被调用,系统是为了保存当前View组件的状态.
   * 在onPause之前被调用.
   */
    @Override
    protected void onSaveInstanceState(Bundle outState) {
        outState.putInt("param", param);
        Log.i(TAG, "onSaveInstanceState called. put param: " + param);
        super.onSaveInstanceState(outState);
    }
     
    /**
     * Activity被系统杀死后再重建时被调用.
     * 例如:屏幕方向改变时,Activity被销毁再重建;当前Activity处于后台,系统资源紧张将其杀死,用户又启动该Activity.
     * 这两种情况下onRestoreInstanceState都会被调用,在onStart之后.
     */
    @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        param = savedInstanceState.getInt("param");
        Log.i(TAG, "onRestoreInstanceState called. get param: " + param);
        super.onRestoreInstanceState(savedInstanceState);
    }
}

이 방법은 특정 상황에서는 여전히 매우 유용합니다. 예를 들어 프로그램 시작 시 특정 뷰 구성 요소의 크기를 가져오려는 경우에는 그렇지 못할 수도 있습니다. Window 개체가 아직 생성되지 않았기 때문에 onCreate에서 가져오려면 지금 onWindowFocusChanged에서 가져와야 합니다. Android 애니메이션용 프레임 애니메이션에 관해 제가 쓴 기사를 읽어보셨다면 그 이유를 아실 것입니다. onCreate에서 프레임 애니메이션을 로드하려는 시도가 실패한 이유는 창 개체가 초기화되지 않았기 때문이므로 결국 onWindowFocusChanged에 애니메이션을 로드하는 코드를 넣었고 문제가 해결되었습니다. 하지만 현재 활동의 모든 작업에는 실행 로그가 있기 때문에 코드에서 이를 주석 처리한 이유가 궁금할 것입니다. 이것이 전체 프로세스의 명확성에 영향을 미칠까 봐 걱정되었기 때문에 모두가 주석 처리하면 됩니다. 적용되는 경우와 실행 순서를 이해합니다.

2.onSaveInstanceState:(1)在Activity被覆盖或退居后台之后,系统资源不足将其杀死,此方法会被调用;(2)在用户改变屏幕方向时,此方法会被调用;(3)在当前Activity跳转到其他Activity或者按Home键回到主屏,自身退居后台时,此方法会被调用。第一种情况我们无法保证什么时候发生,系统根据资源紧张程度去调度;第二种是屏幕翻转方向时,系统先销毁当前的Activity,然后再重建一个新的,调用此方法时,我们可以保存一些临时数据;第三种情况系统调用此方法是为了保存当前窗口各个View组件的状态。onSaveInstanceState的调用顺序是在onPause之前。

3.onRestoreInstanceState:(1)在Activity被覆盖或退居后台之后,系统资源不足将其杀死,然后用户又回到了此Activity,此方法会被调用;(2)在用户改变屏幕方向时,重建的过程中,此方法会被调用。我们可以重写此方法,以便可以恢复一些临时数据。onRestoreInstanceState的调用顺序是在onStart之后。

以上着重介绍了三个相对陌生方法之后,下面我们就来操作一下这个Activity,看看它的生命周期到底是个什么样的过程:

1.启动Activity:

在系统调用了onCreate和onStart之后,调用了onResume,自此,Activity进入了运行状态。

2.跳转到其他Activity,或按下Home键回到主屏:

我们看到,此时onSaveInstanceState方法在onPause之前被调用了,并且注意,退居后台时,onPause后onStop相继被调用。

3.从后台回到前台:

当从后台会到前台时,系统先调用onRestart方法,然后调用onStart方法,最后调用onResume方法,Activity又进入了运行状态。

4.修改TargetActivity在AndroidManifest.xml中的配置,将android:theme属性设置为@android:style/Theme.Dialog,然后再点击LifeCycleActivity中的按钮,跳转行为就变为了TargetActivity覆盖到LifeCycleActivity之上了,此时调用的方法为:

注意还有一种情况就是,我们点击按钮,只是按下锁屏键,执行的效果也是如上。

我们注意到,此时LifeCycleActivity的OnPause方法被调用,并没有调用onStop方法,因为此时的LifeCycleActivity没有退居后台,只是被覆盖或被锁屏;onSaveInstanceState会在onPause之前被调用。

5.按回退键使LifeCycleActivity从被覆盖回到前面,或者按解锁键解锁屏幕:

此时只有onResume方法被调用,直接再次进入运行状态。

6.退出:

最后onDestory方法被调用,标志着LifeCycleActivity的终结。

大家似乎注意到,在所有的过程中,并没有onRestoreInstanceState的出现,这个并不奇怪,因为之前我们就说过,onRestoreInstanceState只有在杀死不在前台的Activity之后用户回到此Activity,或者用户改变屏幕方向的这两个重建过程中被调用。我们要演示第一种情况比较困难,我们可以结合第二种情况演示一下具体过程。顺便也向大家讲解一下屏幕方向改变的应对策略。

首先介绍一下关于Activity屏幕方向的相关知识。

我们可以为一个Activity指定一个特定的方向,指定之后即使转动屏幕方向,显示方向也不会跟着改变:

1.指定为竖屏:在AndroidManifest.xml中对指定的Activity设置android:screenOrientation="portrait",或者在onCreate方法中指定:

setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);//竖屏

2.指定为横屏:在AndroidManifest.xml中对指定的Activity设置android:screenOrientation="landscape",或者在onCreate方法中指定:

setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);//横屏

为应用中的Activity设置特定的方向是经常用到的办法,可以为我们省去不少不必要的麻烦。不过,我们今天讲的是屏幕方向改变时的生命周期,所以我们并不采用固定屏幕方向这种办法。


下面我们就结合实例讲解一下屏幕转换的生命周期,我们新建一个Activity命名为OrientationActivity,如下:

package com.scott.lifecycle;
 
import android.app.Activity;
import android.content.res.Configuration;
import android.os.Bundle;
import android.util.Log;
 
public class OrientationActivity extends Activity {
     
    private static final String TAG = "OrientationActivity";
    private int param = 1;
     
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.orientation_portrait);
        Log.i(TAG, "onCreate called.");
    }
     
    @Override
    protected void onStart() {
        super.onStart();
        Log.i(TAG, "onStart called.");
    }
     
    @Override
    protected void onRestart() {
        super.onRestart();
        Log.i(TAG, "onRestart called.");
    }
     
    @Override
    protected void onResume() {
        super.onResume();
        Log.i(TAG, "onResume called.");
    }
     
    @Override
    protected void onPause() {
        super.onPause();
        Log.i(TAG, "onPause called.");
    }
     
    @Override
    protected void onStop() {
        super.onStop();
        Log.i(TAG, "onStop called.");
    }
     
    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.i(TAG, "onDestory called.");
    }
 
    @Override
    protected void onSaveInstanceState(Bundle outState) {
        outState.putInt("param", param);
        Log.i(TAG, "onSaveInstanceState called. put param: " + param);
        super.onSaveInstanceState(outState);
    }
     
    @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        param = savedInstanceState.getInt("param");
        Log.i(TAG, "onRestoreInstanceState called. get param: " + param);
        super.onRestoreInstanceState(savedInstanceState);
    }
     
    //当指定了android:configChanges="orientation"后,方向改变时onConfigurationChanged被调用
    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        Log.i(TAG, "onConfigurationChanged called.");
        switch (newConfig.orientation) {
        case Configuration.ORIENTATION_PORTRAIT:
            setContentView(R.layout.orientation_portrait);
            break;
        case Configuration.ORIENTATION_LANDSCAPE:
            setContentView(R.layout.orientation_landscape);
            break;
        }
    }
}

首先我们需要进入“Settings->Display”中,将“Auto-rotate Screen”一项选中,表明可以自动根据方向旋转屏幕,然后我们就可以测试流程了,当我们旋转屏幕时,我们发现系统会先将当前Activity销毁,然后重建一个新的:

Android 기본 활동 수명 주기

시스템은 먼저 onSaveInstanceState 메소드를 호출합니다. 임시 매개변수를 Bundle 객체에 저장한 다음 활동이 다시 빌드된 후 이 매개변수를 성공적으로 검색합니다.

이러한 파괴 및 재구성 과정을 방지하려면 AndroidMainfest.xml에서 OrientationActivity에 해당하는 에 대해 android:configChanges="orientation"을 구성한 다음 다시 테스트해 보겠습니다. 4개를 하려면 회전이 다음과 같이 인쇄됩니다.

Android 기본 활동 수명 주기

방향이 회전할 때마다 onConfigurationChanged 메서드만 호출되고 파괴 및 재구성이 없음을 알 수 있습니다. 프로세스.

다음은 주의할 사항입니다.

1. 가 android:screenOrientation 속성으로 구성된 경우 android:configChanges="orientation"이 무효화됩니다.

2. 시뮬레이터와 실제 머신에는 큰 차이가 있습니다. 시뮬레이터에서 android:configChanges 속성이 구성되지 않았거나 구성 값이 방향인 경우 가로 화면으로 전환하고 파괴를 실행합니다. > 다시 빌드하고 세로 화면으로 전환하여 두 번 실행합니다. 실제 기계는 모두 한 번입니다. 시뮬레이터에서 android:configChanges="orientation|keyboardHidden"이 구성되면(Android 4.0인 경우 "orientation|keyboardHidden|screenSize") onConfigurationChanged는 세로 화면으로 전환할 때 한 번, 가로 화면으로 전환할 때 두 번 실행됩니다. 화면. 실제 기계는 모두 한 번입니다.

액티비티의 라이프사이클은 프로그램의 견고성과 불가분의 관계에 있습니다. 친구들이 이를 주의 깊게 이해하고 능숙하게 적용할 수 있기를 바랍니다.


안드로이드 기본 액티비티 생명주기 관련 글을 더 보시려면 PHP 중국어 홈페이지를 주목해주세요!


성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.