Fork me on GitHub

Android Studio教程03-Activtiy生命周期的理解

1. Activity

1.1. 安卓中的Activity定义和特性:

  • 一个Activity就是一个屏幕页面
  • 一个APP中有很多个Activity(打开邮件app,打开具体邮件)
  • APP一般从MainActivity中启动的,当然了,这个也可以修改的
  • APP内的Activity可以通过一些方法(Intent...)进行切换(打开邮件app -> 打开具体邮件)
  • APP之间的Activity也可以互相切换(从浏览器页面 -> facebook页面)

1.2. 注册Activity

进入AndroidManifest.xmlapplication下添加一个activity元素

1. Intent filters:设置默认开启的activity

Intent filters可以显示或者隐式的启动activity,我们可以利用这个属性来扩展activity功能

<activity 
  android:name=".MainActivity"
  android:label="FirstPage"
  android:icon="@drawable/app_icon">
  <!--intent-filter放在哪个activity,这个actiivty就是默认启动的activity-->
    <intent-filter>
        <!--action:这个activity可以发送数据-->
        <action android:name="android.intent.action.SEND" />
        <!--category:这个activity可以接收请求-->
        <category android:name="android.intent.category.DEFAULT" />
        <!--data:这个activity可以接收数据类型-->
        <data android:mimeType="text/plain" />
    </intent-filter>
</activity>

<activity
  android:name=".SecondActivity"
  android:label="SecondPage"
  ></activity>

程序调用过程

// Create the text message with a string
Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.setType("text/plain");
sendIntent.putExtra(Intent.EXTRA_TEXT, textMessage);
// Start the activity
startActivity(sendIntent);

1.3. Activity的启动流程

插入activity01.md
插入activity02.md

1.4. 如何控制activity中的内容

通过代表控件的对象来更改控件内容

2. Android的生命周期

首先我们来看一下谷歌官网发布的图

声明周期函数 调用时机 所处状态 应该执行的操作
onCreate 在Activity对象第一次创建时调用 Created 初始化操作(只执行一次的操作)
调用setContentView()设置界面布局
onStart 当Activity变得可见时调用该函数 Started 组件的初始化操作,建议放再onResume中
onResume 当Activity开始准备与用户交互时调用该方法 Resumed 最常见的操作都需要放在这里(最重要的部分)
onPause 当系统即将开启另外一个Activity之前调用 Paused 停止一些可能影响电池的操作,清除一些轻度的占用CPU任务(关闭相机)
onStop 当前Activity变得不可见时调用 Stopped 当屏幕不可见的时候,清除或者调整一些操作
保存数据库的最好位置
onDestroy 当前Activity被销毁之前将会调用 清除所有占用内存的任务
onRestart 当一个Activity再起启动之前会调用 -> Resumed

onCreate()

  • 作用: 初始化 + 进入启动阶段
  • 在Activity对象第一次被创建时调用,必须重写
  • 那么在onCreate() 应该执行一些什么操作呢?
    • 在整个生命周期只需要执行一次的操作
    • 初始化 Activity 的必需组件
    • 调用setContentView()来定义用户界面的布局
  • 接收的参数为savedInstanceState:表示活动前所保存的状态,如果这个活动之前没有启动过,那么Bundle的值为null
  • onCreate() 之后:进入启动阶段
TextView mTextView;

// some transient state for the activity instance
String mGameState;

@Override
public void onCreate(Bundle savedInstanceState) {
    // 调用父类的onCreate方法
    super.onCreate(savedInstanceState);

    // recovering the instance state
    if (savedInstanceState != null) {
        mGameState = savedInstanceState.getString(GAME_STATE_KEY);
    }

    // 设置界面布局文件(res/layout/main_activity.xml)
    setContentView(R.layout.main_activity);

    // 初始化一些部件,这样在下面的方法中可以操作
    mTextView = (TextView) findViewById(R.id.text_view);
}

// This callback is called only when there is a saved instance that is previously saved by using
// onSaveInstanceState(). We restore some state in onCreate(), while we can optionally restore
// other state here, possibly usable after onStart() has completed.
// The savedInstanceState Bundle is same as the one used in onCreate().
@Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
    mTextView.setText(savedInstanceState.getString(TEXT_VIEW_KEY));
}

// invoked when the activity may be temporarily destroyed, save the instance state here
@Override
public void onSaveInstanceState(Bundle outState) {
    outState.putString(GAME_STATE_KEY, mGameState);
    outState.putString(TEXT_VIEW_KEY, mTextView.getText());

    // call superclass to save any view hierarchy
    super.onSaveInstanceState(outState);
}

onStart()

  • 作用: 使Activity可见,可视化页面会显示出来 + 进入Resume阶段
  • 特性:
    • 完成得特别快
    • 一旦执行完成,直接进入onResume()阶段
    • 所有生命周期组件会收到onStart()事件

onResume()

  • 作用: app可以和用户交互
  • 特性:
    • app会一直停留在这个阶段,直到有什么操作打断他(来电话啦...)
    • 所有生命周期组件会收到onResume()事件
    • 当有异常时,会进入暂停阶段,处罚onPause()方法
    • 当异常结束重新进入Resume阶段时,又会重新调用onResume()
    • 你应该在这段代码中写一些初始化组件的代码
  • 建议: 如果在onStart()中初始化一些组件后,记得在onStop()释放

onPause()

  • 当acitivty不再前端的时候(即使在多窗口模式中,它是visible模式), app进入这个阶段
  • 使用onPause()方法来停止或者调整操作,当activity不再主界面的时候
  • acitivity进入这个阶段的原因如下:
    • 一些中断了app运行
    • 多窗口模式下,一个app启动会自动让另外的app进入onpause状态
    • 有些情况下,即使activity是visible模式,它也会进入这个onPause阶段
  • 所有生命周期组件会收到onPause()事件,这里我们可以停止一些操作
  • 这个阶段的任务:
    • 可以停止一些你不想运行的操作(关闭camera..)
    • 释放一些系统资源,处理sensors或者其他会影响电源的组件(但是推荐使用onStop()方法
    • 千万不要在这里保存数据,网络操作,或者数据库操作
    • 注意: 完成这个阶段并不意味着activity离开了onPause阶段,如果acitivty进入Resume阶段,调用onResume,如果actiivty完全不可见,进入onStop()阶段,否则一直在onPause阶段
public class JavaCameraComponent implements LifecycleObserver {

    ...
    // 一旦收到`onPause`事件。释放camera
    @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
    public void releaseCamera() {
        if (camera != null) {
            camera.release();
            camera = null;
        }
    }

    ...
}

onStop()

  • 什么时候发生:activity完全不可见
  • 所有生命周期组件会收到onStop()事件,这里我们可以停止一些操作
  • 在这个阶段的任务
    • 释放一些heavy的任务
    • 关闭一些CPU重的任务
    • 这是保存到数据库的绝佳位置
@Override
protected void onStop() {
    // call the superclass method first
    super.onStop();

    // save the note's current draft, because the activity is stopping
    // and we want to be sure the current note progress isn't lost.
    ContentValues values = new ContentValues();
    values.put(NotePad.Notes.COLUMN_NAME_NOTE, getCurrentNoteText());
    values.put(NotePad.Notes.COLUMN_NAME_TITLE, getCurrentNoteTitle());

    // do this update in background on an AsyncQueryHandler or equivalent
    mAsyncQueryHandler.startUpdate (
            mToken,  // int token to correlate calls
            null,    // cookie, not used here
            mUri,    // The URI for the note to update.
            values,  // The map of column names and new values to apply to them.
            null,    // No SELECT criteria are used.
            null     // No WHERE columns are used.
    );
}

onDestroy()

  • 进入这个阶段的原因:
    • activity完成(用户取消activity,或者调用了finish()方法)
    • 系统自动删除activity(手机转动,或者多窗口模式下)
  • 所有生命周期组件会收到onDestroy()事件,这里我们可以所有需要停止的东西

3. Activity生命周期被回收的几率表

被杀的可能性 过程状态 Activity状态
最小 前端 Created
Started
Resumed
中等 后端(lost focus) Paused
最高 后端(不可见)
Stopped
destroyed

4. 保存和储存短暂的UI状态

考虑如下两种情况

  • 用户转换屏幕或者切换到多窗口模式时,系统会默认摧毁之前的activity,但是用户希望能够保持原来的activity不变
  • 用户有时候可能一不小心从当前app切换到其他app,系统会默认摧毁之前的activity,当然我们希望用户切换回来的时候还是保持当前的状态

解决方法: 保存UI状态:ViewModel + obSaveInstanceState()

4.1. Instance state

  • 系统用于保存之前状态的过程为Instance state--其实是一些保存在Bundle对象的键值对
  • 系统默认使用BundleInstance state来保存每个View的信息(比如EditText中的文本)

4.2.通过onSaveInstanceState()保存一些轻度,简单的UI状态

  • 当Activity准备停止的时候,系统就会调用onSaveInstanceState()来保存一些基本的信息,比如edittext中的value..
  • 如果你想要保存更多的内容,需要重写onSaveInstanceState()方法,添加新的key-value对到Bundle对象中
  • 如果重写onSaveInstanceState()方法,一定调用super implmenetaion
static final String STATE_SCORE = "playerScore";
static final String STATE_LEVEL = "playerLevel";
// ...


@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
    // Save the user's current game state
    savedInstanceState.putInt(STATE_SCORE, mCurrentScore);
    savedInstanceState.putInt(STATE_LEVEL, mCurrentLevel);

    // Always call the superclass so it can save the view hierarchy state
    super.onSaveInstanceState(savedInstanceState);
}

4.3. 通过保存的UI状态恢复活动的UI

  • 我们可以在onCreateonRestoreInstanceState()中调用Bundle对象来恢复UI
    • onCreate:只有当创建一个新的activtiy实例,才会调用这个方法,必须坚持Bundle是否为空,空的话,创建新的实例,不是空的话,恢复之前的UI
    • onRestoreInstanceState():这个方法在onStart()方法之后调用,系统只会在Bundle不为空的时候调用,所以你不用检查是否为null
// method 1
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState); // Always call the superclass first

    // Check whether we're recreating a previously destroyed instance
    if (savedInstanceState != null) {
        // Restore value of members from saved state
        mCurrentScore = savedInstanceState.getInt(STATE_SCORE);
        mCurrentLevel = savedInstanceState.getInt(STATE_LEVEL);
    } else {
        // Probably initialize members with default values for a new instance
    }
    // ...
}

// method2
public void onRestoreInstanceState(Bundle savedInstanceState) {
    // Always call the superclass so it can restore the view hierarchy
    super.onRestoreInstanceState(savedInstanceState);

    // Restore state members from saved instance
    mCurrentScore = savedInstanceState.getInt(STATE_SCORE);
    mCurrentLevel = savedInstanceState.getInt(STATE_LEVEL);
}

5.Activity之间是如何切换的?

5.1 从一个Activity切换到另外一个Activity:

1. startActivity()

  • 如果不需要返回一个结果,就用这个
Intent intent = new Intent(this, SignInActivity.class);
startActivity(intent);

你也可以通过startActivity启动一些以后的组件来扩展功能(调用Email的app)

Intent intent = new Intent(Intent.ACTION_SEND);
intent.putExtra(Intent.EXTRA_EMAIL, recipientArray);
startActivity(intent);

The EXTRA_EMAIL extra added to the intent is a string array of email addresses to which the email should be sent. When an email application responds to this intent, it reads the string array provided in the extra and places them in the "to" field of the email composition form. In this situation, the email application's activity starts and when the user is done, your activity resumes.

2.startActivityForResult()

  • 当你需要从即将结束的Activity中返回一个值的时候用这个,比如你从当前activity的列表中选中一个水果,你想要保存这个选中的水果
  • 当有一个子类Activity的时候,它可以调用setResult(int)来返回数据给他的父类Activity
  • 父类Activity使用onActivityResult(int, int, Intent) 来获取信息
public class MyActivity extends Activity {
     // ...

     static final int PICK_CONTACT_REQUEST = 0;

     public boolean onKeyDown(int keyCode, KeyEvent event) {
         if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) {
             // When the user center presses, let them pick a contact.
             startActivityForResult(
                 new Intent(Intent.ACTION_PICK,
                 new Uri("content://contacts")),
                 PICK_CONTACT_REQUEST);
            return true;
         }
         return false;
     }

     protected void onActivityResult(int requestCode, int resultCode,
             Intent data) {
         if (requestCode == PICK_CONTACT_REQUEST) {
             if (resultCode == RESULT_OK) {
                 // A contact was picked.  Here we will just display it
                 // to the user.
                 startActivity(new Intent(Intent.ACTION_VIEW, data));
             }
         }
     }
 }

6.Activity的几种状态

状态 产生原因 调用方法
配置变化 转屏幕
更改语言
插入设备
原activity被销毁:onPause()->onStop()->onDestroy()
原activity被重建:onCrate()->onStart()->onResume()
新的activity或者对话框显示 比如弹出一个对话框-> 导致被覆盖的activity暂停 新的activity半覆盖: onPause()>onResume()
新的activity全覆盖:onPause()->onStop()->onRestart()->onStart()->onResume()
点击返回按钮 点击Back按钮 原activity: onPause()->onStop()->onDestroy()->remove from back stack
onSaveInstanceState() not work
你可以重写onBaclPressed
系统杀死app 系统需要释放内存 ....

7.实例演示Activity的生命周期

创建两个activity: mainactivity和otheractivity

public class OtherActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_other);
        Toolbar toolbar = findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        FloatingActionButton fab = findViewById(R.id.fab);
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
                        .setAction("Action", null).show();
            }
        });
        System.out.println("--OtherActivity: OnCreate--");
    }

    @Override
    protected void onStart() {
        super.onStart();
        System.out.println("--OtherActivity: OnStart--");
    }

    @Override
    protected void onResume() {
        super.onResume();
        System.out.println("--OtherActivity: OnResume--");
    }

    @Override
    protected void onPause() {
        super.onPause();
        System.out.println("--OtherActivity: OnPause--");
    }

    @Override
    protected void onStop() {
        super.onStop();
        System.out.println("--OtherActivity: OnStop--");
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        System.out.println("--OtherActivity: OnDestroy--");
    }

    @Override
    protected void onRestart() {
        super.onRestart();
        System.out.println("--MainActivity: OnRestart--");
    }
}

otherActivity也差不多,然后执行程序

当程序呈现第一个页面的时候,打印的信息是:

当点击按钮,进入第二个activity的时候:

当点击返回按钮返回主activity的时候:

posted @ 2019-01-16 20:23  Bricker666  阅读(2230)  评论(0编辑  收藏  举报