技術の学習も同様で、専門書や古典的な専門書は一度読んだだけでは完全に理解することは基本的に不可能なので、何度も読み返して著者の考えの本質を理解する必要があります。 。
最近、Activityのライフサイクルを見直し、関連書籍や公式ドキュメントを読んで、以前の理解が大幅に深まったので、ここで共有したいと思います。
JavaEE に精通している友人は皆、サーブレット テクノロジを知っています。独自のサーブレットを実装したい場合は、対応する基本クラスを継承し、そのメソッドを適切なタイミングで呼び出す必要があります。 。実際、Android のアクティビティ実行メカニズムはサーブレットに似ています。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 メソッドを呼び出して現在のアクティビティを終了します。
しかし、これらを知っているだけでは十分ではなく、深く理解して理解するには、自分で試してみる必要があります。
次に、例を使用して、ライフサイクル内のいくつかのプロセスの詳細を示します。
次のように、lifecycle という新しいプロジェクトを作成し、LifeCycleActivity というアクティビティを作成します。
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); } }
皆さんは、いくつかの一般的なメソッドに加えて、onWindowFocusChanged、onSaveInstanceState、および onRestoreInstanceState メソッドも追加していることに気づきました:
1 .onWindowFocusChanged メソッド:アクティビティ ウィンドウが作成されたときに最初にユーザーに表示されたとき、または現在のアクティビティが他のアクティビティに切り替わったとき、またはホーム ボタンを押して元のアクティビティに戻ったときなど、アクティビティ ウィンドウがフォーカスを取得したとき、またはフォーカスを失ったときに呼び出されます。ホーム画面に戻り、ユーザーは現在のアクティビティを終了します。 OnWindowFocusChanged は上記の状況で呼び出され、アクティビティが作成されると、onResume の後に呼び出されます。アクティビティが上書きされるかバックグラウンドに戻るか、現在のアクティビティが終了すると、図に示すように onPause の後に呼び出されます。
このメソッドは、特定の状況では依然として非常に役立ちます。たとえば、プログラムの開始時に特定のビュー コンポーネントのサイズを取得したい場合、ウィンドウ オブジェクトが持っているため、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销毁,然后重建一个新的:
システムは最初に onSaveInstanceState メソッドを呼び出し、一時パラメータを Bundle オブジェクトに保存し、アクティビティが再構築された後にこのパラメータを正常に取得します。
この破壊と再構築のプロセスを回避するには、AndroidMainfest.xml の OrientationActivity に対応する
方向が回転されるたびに onConfigurationChanged メソッドのみが呼び出され、破棄および再構築のプロセスがないことがわかります。
以下は注意すべき点です:
1.
2. シミュレーターと実機には大きな違いがあります。シミュレーターで android:configChanges 属性が設定されていない場合、または設定値が Orientation である場合、横画面に切り替えるときに一度破棄されます -> リビルド、縦画面に切り替わったときに2回。実機は全て一度限りです。シミュレータで android:configChanges="orientation|keyboardHidden" が設定されている場合 (Android 4.0 の場合は "orientation|keyboardHidden|screenSize")、onConfigurationChanged は縦画面に切り替えるときに 1 回、横画面に切り替えるときに 2 回実行されます。画面。実機は全て一度限りです。
アクティビティのライフサイクルはプログラムの堅牢性と切り離せないものであり、友人がそれを注意深く理解し、上手に適用できることを願っています。
Android の基本のアクティビティ ライフ サイクルに関連するその他の記事については、PHP 中国語 Web サイトに注目してください。