此前,重溫了一下《android第一行代碼》第二版,在這裏做個小小的記錄。
一、活動週期
返回棧
android是使用任務(Task)管理活動的,一個任務就是一組存放在棧裏的活動的集合,這個棧也被稱作返回棧(Back Stack)。棧的特點就是後進先出,我們這裏的活動也是一樣。
活動狀態
我們這裏根據在棧中所在位置進行判斷。
1、運行狀態
一個活動位於返回棧的棧頂
2、暫停狀態
一個活動不處於棧頂,但依然可見(例如活動只佔了一部分屏幕的情形,只有在內存極低的情況下,系統纔會考慮回收這種活動)
3、停止狀態
一個活動不再處於棧頂,並且完全不可見時(當其他地方需要內存時,處於停止狀態的活動有可能會被系統回收)
4、銷燬狀態
一個活動從返回棧中移除
活動的生存週期
- onCreate():它會在活動第一次被創建的時候調用。在這個方法中完成活動的初始化操作,比如 說加載佈局、綁定事件等。
- onStart():這個方法在活動由不可見變爲可見的時候調用。
- onResume():這個方法在活動準備好和用戶進行交互的時候調用。此時的活動一定位於返回棧的棧頂,並且處於運行狀態。
- onPause():這個方法在系統準備去啓動或者恢復另一個活動的時候調用。我們通常會在 這個方法中將一些消耗CPU的資源釋放掉,以及保存一些關鍵數據,但這個方法的執行 速度一定要快,不然會影響到新的棧頂活動的使用。
- onStopO:這個方法在活動完全不可見的時候調用。它和0nPauseO方法的主要區別在 於,如果啓動的新活動是一個對話框式的活動,那麼onPause()方法會得到執行,而 onStopO方法並不會執行。
- onDestroy():這個方法在活動被銷燬之前調用,之後活動的狀態將變爲銷燬狀態。
- onRestart():這個方法在活動由停止狀態變爲運行狀態之前調用,也就是活動被重新啓動了。
以上7個方法中除了 onRestart()方法,其他都是兩兩相對的,從而又可以將活動分爲3 種生存期。
- 完整生存期。活動在onCreateO方法和onDestroyO方法之間所經歷的,就是完整生存期。一般情況下,一個活動會在onCreateO方法中完成各種初始化操作,而在 onDestroyO方法中完成釋放內存的操作。
- 可見生存期。活動在onStartO方法和onStopO方法之間所經歷的,就是可見生存期。 在可見生存期內,活動對於用戶總是可見的,即便有可能無法和用戶進行交互。我們可 以通過這兩個方法,合理地管理那些對用戶可見的資源。比如在onStart()方法中對資 源進行加載,而在onStopO方法中對資源進行釋放,從而保證處於停止狀態的活動不會 佔用過多內存。
- 前臺生存期。活動在onResumeO方法和onPauseO方法之間所經歷的就是前臺生存期。 在前臺生存期內,活動總是處於運行狀態的,此時的活動是可以和用戶進行交互的,我 們平時看到和接觸最多的也就是這個狀態下的活動。
活動回收丟失數據問題
活動在回收前一定會回調onSaveInstanceState()方法。
onSaveInstanceState()方法會攜帶一個Bundle類型的參數,Bundle提供了一系列的方法用於保存數據,比如可以使用putString()方法保存字符串,使用putlnt()方法保存整型數據,以鍵值對保存。
在MainActivity中添加如下代碼就可以將臨時數據進行保存
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSavelnstanceState(outState);
String tempData = "Something you just typed";
outState.putString("datakey", tempData);
}
數據恢復:
修改MainActivity的onCreate ()方法
@Override
protected void onCreate(Bundle savedlnstanceState) {
super.onCreate(savedlnstanceState);
Log.d(TAG, "onCreate"); setContentView(R.layout.activitymain);
if (savedlnstanceState != null) {
String tempData = savedlnstanceState.getString("data^key");
Log. d(TAG, tempData);
}
}
二、活動的啓動模式
啓動模式一共有4種,分別是standard.、singleTop.、singleTask和 singlelnstance,可以在 AndroidManifest.xml 中通過給<activity>標籤指定 android: launchMode 屬性來選擇啓動模式。
standard
standard是活動默認的啓動模式,在不進行顯式指定的情況下,所有活動都會自動使用這種啓動模式。每當啓動一個新的活動,它就會在返回棧中入棧,並處於棧頂的位置。對於使用standard模式的活動, 系統不會在乎這個活動是否已經在返回棧中存在,每次啓動都會創建該活動的一個新的實例。
@Override
protected void onCreate(Bundle savedlnstanceState) {
super.onCreate(savedlnstanceState);
Log.d("FirstActivity", this.toString());
setContentView(R.layout.firstlayout);
Button buttonl = (Button) findViewByld(R.id.buttonl);
buttonl.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(FirstActivity.this, FirstActivity.class);
startActivity(intent);
}
});
}
在活動中調用活動本身,會發現調用了幾次,返回也要幾次。
singleTop
當活動的啓動模式指定爲 singleTop,在啓動活動時如果發現返回棧的棧頂已經是該活動,則認爲可以直接使用它,不會再創建新的活動實例。
<activity
android:name=".FirstActivity"
android :launchMode="singleTop"
android:label="This is FirstActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
如果該活動並沒有處於棧頂的位置,還是可能會創建多個活動實例的
singleTask
每次啓動該活動時系統首先會在返回棧中檢查是否 存在該活動的實例,如果發現已經存在則直接使用該實例,並把在這個活動之上的所有活動統統出棧,如果沒有發現就會創建一個新的活動實例。
<activity
android:name=".FirstActivity"
android: LaunchMode=llsingleTaskl>
android:label="This is FirstActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
活動的最佳實踐
知曉當前是在哪一個活動
新建一個BaseActivity類(java類)
public class BaseActivity extends AppCompatActivity {
©Override
protected void onCreate(Bundle savedlnstanceState) {
super.onCreate(savedlnstanceState);
Log.d("BaseActivity", getClass().getSimpleName());
}
}
然後讓其他類繼承該類,現在每當我們進入到一個活動的界面,該活動的類名就會被打印出來,這樣我們就可以時時 刻刻知曉當前界面對應的是哪一個活動了。
隨時隨地退出程序
新建一個Activitycollector類作爲活動管理器
public class Activitycollector {
public static List<Activity> activities = new ArrayList<>();
public static void addActivity(Activity activity) {
activities.add(activity);
}
public static void removeActivity(Activity activity) {
activities.remove(activity);
}
public static void finishAH() {
for (Activity activity : activities) {
if (!activity.isFinishing()) {
activity.finish();
}
}
}
}
接下來修改BaseActivity中的代碼,如下所示:
public class BaseActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedlnstanceState) {
super.onCreate(savedlnstanceState);
Log.d("BaseActivity", getClassO.getSimpleName());
ActivityCollector.addActivity(this):
}
@Override
protected void onDestroy() {
super.onDestroy();
ActivityCollector.removeActivity(this);
}
}
從此以後,不管你想在什麼地方退出程序,只需要調用ActivityCollector. finishAll () 方法就可以了。
當然你還可以在銷燬所有活動的代碼後面再加上殺掉當前進程的代碼,以保證程序完全退 出,殺掉進程的代碼如下所示:
android.os.Process.killProcess(android.os.Process.myPid());
其中,killProcessO方法用於殺掉一個進程,它接收一個進程id參數,我們可以通過 myPid()方法來獲得當前程序的進程ido需要注意的是,killProcessO方法只能用於殺掉當前 程序的進程,我們不能使用這個方法去殺掉其他程序。
啓動活動的最佳寫法
即將所有Intent封裝到一個方法裏面。
public class SecondActivity extends BaseActivity {
public static void actionstart(Context context, String datal, String data2) {
Intent intent = new Intent(context, SecondActivity.class);
intent.putExtra("paraml", datal);
intent.putExtra("param2", data2);
context.startActivity(intent);
}
}
這樣傳送的數據就能一目瞭然