Activity生命週期
Activity的生命週期包括onCreate(),onRestart(),onStart(),onResume(),onPause(),onStop(),onDestroy()。其相互轉化的過程如下圖所示。左邊的圖是單個Activity的生命週期回撥情況。右邊的是當前Activity跳轉到另外一個Activity時,兩者相關生命週期回撥先後順序的情形。
onCreate()
表示Activity正在被建立
此方法在整個生命週期中只會被呼叫一次。可以在這裡做一些初始化的操作。
引數savedInstanceState儲存Activity因為異常情況而被銷燬前的狀態,可以利用此引數做一些資料恢復的操作。
onStart()
表示Activity正在被啟動。此時Activity已經可見,即將進入前臺介面,但是還不能喝使用者進行互動。
onResume()
表示Activity已經啟動完成,進入到了前臺,可以同使用者進行互動了。需要注意的是此方法在Activity的整個生命週期中可能會被多次呼叫到。
onPause()
表示Activity正在被停止。
可以在這裡釋放系統資源,動畫的停止
不宜在此做耗時操作,因為此方法結束後會呼叫新Activity的onCreate(),onStart(),onResume(),耗時操作會影響到新Activity的顯示
onStop()
當Activity不可見的時候回撥此方法。
需要在這裡釋放全部使用者使用不到的資源。
可以做較重量級的工作,如對註冊廣播的解註冊,對一些狀態資料的儲存
此時Activity還不會被銷燬掉,而是保持在記憶體中,但隨時都會被回收。
onDestroy()
Activity即將被銷燬。
此時會釋放掉所有佔用的資源。
通常的:
onCreate()和onDestroy()成對存在
onStart()和onStop()成對存在
onResume()和onPause()成對存在
Activity狀態的儲存和恢復
狀態的儲存
當Activity 非正常退到後臺時,就會呼叫onSaveInstanceState()方法。非正常的情況包括:有新的Activity啟動,滅屏,未設定儲存狀態的橫豎屏切換,按home鍵到桌面,切換到最近任務列表。正常情況是使用者點選返回鍵,程式呼叫finish()方法,此時不會回撥onSaveInstanceState()方法。
呼叫的次序為:onPause()->onSaveInstanceState()->onStop()
可對一些狀態進行儲存,
static final String STATE_LISTVIEW_CURRENT_POSITION = "list_view_current_position";
...
@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
// 儲存當前ListView的位置
savedInstanceState.putInt(STATE_LISTVIEW_CURRENT_POSITION , mCurrentPosition);
// Always call the superclass so it can save the view hierarchy state
super.onSaveInstanceState(savedInstanceState);
}複製程式碼
系統會為View自動儲存相關的狀態,前提是View要在佈局檔案裡設定唯一的id值,即android:id屬性。
由於onSaveInstanceState()方法不能保證百分百呼叫到,所以只能做一些臨時狀態資訊的儲存,如果要做持久化的操作,需要在onStop()裡進行。
狀態的恢復
當Activity在被銷燬後重新建立時,可以從onCreate(Bundle savedInstanceState)方法中的savedInstanceState引數恢復之前儲存的狀態,也可以從onRestoreInstanceState(Bundle savedInstanceState)方法中恢復。兩種方法的效果都是一樣的,只是前者需要判空操作,後者不需要
onCreate(Bundle savedInstanceState)的恢復:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//如果不為空的話,則說明有可恢復的狀態
if (savedInstanceState != null) {
mCurrentPosition= savedInstanceState.getInt(STATE_LISTVIEW_CURRENT_POSITION );
} else {
//初始化
}
...
}複製程式碼
onRestoreInstanceState(Bundle savedInstanceState)的恢復:
//呼叫此方法,savedInstanceState引數必不為空
public void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
mCurrentPosition= savedInstanceState.getInt(STATE_LISTVIEW_CURRENT_POSITION );
}複製程式碼
Activity啟動模式
四種啟動模式
Activity的啟動模式可以允許你的Activity擁有多少個例項。
有兩種方法可以設定:1、在manifest檔案中設定。2、用Intent的flag標識設定
manifest方式
在minifest中對應的Activity設定如下四個中的一個值。
...
<activity
...
android:launchMode=["standard" | "singleTop" | "singleTask" | "singleInstance"]
...
/>
...複製程式碼
standard
預設值,多例項模式。
每啟動一次,都會建立一個新的Activity例項。
並且新例項可以在不同的任務棧上建立,相同的任務棧可以建立多個例項。
啟動的生命週期為:onCreate()->onStart()->onResume()
需要注意的是,此模式下啟動的例項所在的任務棧,為啟動它的那個Activity所屬的任務棧。比如A屬於task1,A啟動了B,B的模式為standard,則B所在的任務棧為task1
singleTop
棧頂複用模式
如果任務棧頂已經存在需要啟動的目標Activity,則直接啟動,並會回撥onNewIntent()方法,生命週期順序為:
onPause() ->onNewIntent()->onResume()
如果任務棧上頂沒有需要啟動的目標Activity,則建立新的例項,此時生命週期順序為:
onCreate()->onStart()->onResume()
兩種情況如下圖,從圖中可以看出,此模式下還是會出現多例項,只要啟動的目標Activity不在棧頂的話。
singleTask
棧內複用模式,一個任務棧只能有一個例項。
有幾種情況:
當啟動的Activity目標任務棧不存在時,則以此啟動Activity為根Activity建立目標任務棧,並切換到前面
當啟動的Activity目標任務棧存在,啟動的Activity不存在時,則直接在目標任務棧上建立Activity
當啟動的Activity存在時,則會直接切換到Activity所在的任務棧,並且任務棧中在Activity上面的所有其他Activity都出棧(呼叫destroy()),此時啟動的Activity位於任務棧頂,並且會回撥onNewIntent()方法。
singleInstance
和singleTask模式類似,只不過獨佔其所在的任務棧,比如A為singleInstance模式,其所需的任務棧為task1,則task1只有A一個Activity,由A啟動的Activity會另起一個task。而後續啟動此Activity,都不會再建立新的Activity。
Intent的方式
除了可以在manifest中設定Activity的啟動模式,也可以通過設定Intent的flag標識來設定Activity的啟動模式。
常用的有:FLAG_ACTIVITY_NEW_TASK,FLAG_ACTIVITY_SINGLE_TOP,FLAG_ACTIVITY_CLEAR_TOP
FLAG_ACTIVITY_NEW_TASK
啟動Activity時,如果不存在Activity的例項,則會以此Activity為根Activity建立新的任務棧,如果存在的話則直接切換到對應的Activity例項,並回撥onNewIntent()方法。相當於“singleTask”啟動模式。
FLAG_ACTIVITY_SINGLE_TOP
相當於“singleTop”模式
FLAG_ACTIVITY_CLEAR_TOP
設定此標識的Activity在啟動時,如果當前的任務棧記憶體在此Activity例項,則跳轉到此例項,並清除掉在此例項上面的所有Activity例項,此時此Activity例項位於任務棧的棧頂
Activity間的資料傳遞
Activity直接的資料傳遞,一般使用Intent就夠了。
可以使用Intent.putExtra()方法
把值傳給待啟動的Activity
//MianActivity
Intent intent = new Intent(this, SecondActivity.class);
intent.putExtra("data_key", "abcd");
Bundle data = new Bundle();
data.putString("key1","value1");
intent.putExtra("data",data);
...
startActivity(intent);
...
//SecondActivity
...
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.my_activity_layout);
Intent intent = getIntent();
Toast.makeText(this,intent.getStringExtra("data_key"),Toast.LENGTH_LONG).show();
Bundle data = intent.getBundleExtra("data");
String key1 = data.getString("key1");
Toast.makeText(this,key1,Toast.LENGTH_LONG).show();
}
...複製程式碼
把值返回給啟動它的Activity
Intent intent = new Intent(MainActivity.this,SecondActivity.class);
startActivityForResult(intent, REQUEST_CODE);
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
String str = data.getStringExtra("data");
if(REQUEST_CODE == requestCode){
if(SecondActivity.RESULT_CODE == resultCode){
...
}
}
...
}
...
//SecondActivity
...
Intent intent = new Intent();
intent.putExtra("data", "result_value");
setResult(RESULT_CODE, intent);
finish();
...複製程式碼