[TOC] 1. Activity 1.1. 安卓中的Activity定義和特性: 一個Activity就是一個屏幕頁面 一個APP中有很多個Activity(打開郵件app,打開具體郵件) APP一般從MainActivity中啟動的,當然了,這個也可以修改的 APP內的Activity可以通過一 ...
目錄
- 1. Activity
- 2. Android的生命周期
- 3. Activity生命周期被回收的幾率表
- 4. 保存和儲存短暫的UI狀態
- 5.Activity之間是如何切換的?
- 6.實例演示Activity的生命周期
1. Activity
1.1. 安卓中的Activity定義和特性:
- 一個Activity就是一個屏幕頁面
- 一個APP中有很多個Activity(打開郵件app,打開具體郵件)
- APP一般從MainActivity中啟動的,當然了,這個也可以修改的
- APP內的Activity可以通過一些方法(Intent...)進行切換(打開郵件app -> 打開具體郵件)
- APP之間的Activity也可以互相切換(從瀏覽器頁面 -> facebook頁面)
1.2. 註冊Activity
進入AndroidManifest.xml
在application
下添加一個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階段
- 一些中斷了app運行
- 所有生命周期組件會收到
onPause()
事件,這裡我們可以停止一些操作
- 這個階段的任務:
- 可以停止一些你不想運行的操作(關閉camera..)
- 釋放一些系統資源,處理sensors或者其他會影響電源的組件(但是推薦使用onStop()方法)
- 千萬不要在這裡保存數據,網路操作,或者資料庫操作
- 註意: 完成這個階段並不意味著activity離開了onPause階段,如果acitivty進入Resume階段,調用
onResume
,如果actiivty完全不可見,進入onStop()
階段,否則一直在onPause
階段
- 可以停止一些你不想運行的操作(關閉camera..)
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. ); }
- 釋放一些heavy的任務
onDestroy()
- 進入這個階段的原因:
- activity完成(用戶取消activity,或者調用了finish()方法)
- 系統自動刪除activity(手機轉動,或者多視窗模式下)
- activity完成(用戶取消activity,或者調用了finish()方法)
- 所有生命周期組件會收到
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
對象的鍵值對
- 系統預設使用
Bundle
的Instance 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
- 我們可以在
onCreate
和onRestoreInstanceState()
中調用Bundle
對象來恢復UIonCreate
:只有當創建一個新的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: 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也差不多,然後執行程式