目錄
一、什么是Activity
二、如何創建和配置Activity
三、Activity 跳轉與數據傳遞
四、數據保存與恢復
五、Activity 啟動模式
六、自定義返回行為
七、復雜界面布局
你可以把Activity想象成手機屏幕上的一個“頁面”。比如,當你打開一個App時,看到的第一個界面就是一個Activity;點擊某個按鈕跳轉到另一個界面,那就是另一個Activity。每個Activity就是一個獨立的“屏幕”,負責展示內容和與用戶交互。
一、什么是Activity
Activity? 是 Android 應用的核心交互組件。
1?.?單屏交互容器?
- 每個 Activity 對應一個獨立的用戶界面(UI)屏幕;
- 此界面承載用戶可見的視圖控件,如按鈕、文本框等;
- 用戶可在此界面進行交互操作,如點擊、輸入等。
- 應用通常包含多個 Activity,通過跳轉實現不同功能界面的切換。
2?.?生命周期管理
?
onCreate():Activity被創建時調用。通常會在這里初始化界面和變量,這時我們看到的是一片空白。
onStart():Activity即將可見時調用。此后頁面可見,但用戶還不能跟頁面進行互動。
onResume():Activity獲得焦點,用戶可以與之交互時調用。
onPause():Activity失去焦點時調用。比如,用戶按了Home鍵回到桌面,或者跳轉到另一個頁面,但頁面還沒有完全不可見。
onStop():Activity不再可見時調用。比如,你點擊文章詳情頁跳轉到了文章里面。首頁面被完全覆蓋。onRestart():Activity從停止狀態重新啟動時調用。首頁Activity從后臺回到前臺,準備重新顯示。
onDestroy():Activity被銷毀時調用。比如,用戶關閉了頁面
3. 跨組件通信?
- 使用 ?Intent? 與其他 Activity 或組件傳遞數據或啟動新界面。
Intent intent = new Intent(MainActivity.this, SecondActivity.class);
intent.putExtra("key", "value");
startActivity(intent);
4. 關鍵功能
- ?用戶事件處理?:監聽觸摸、按鍵等操作,響應交互邏輯。
- ?界面動態更新?:根據業務需求更新 UI 元素(如列表數據刷新)。
- ?資源管理?:在?
onDestroy()
?中釋放數據庫連接、網絡請求等資源,避免內存泄漏。
5.?門店與后廚模型?
- Activity 類似“門店”(直接面向用戶),負責展示和接收指令;
- Service 類似“后廚”(后臺處理任務),通過 Intent(“訂單”)傳遞需求。
二、如何創建和配置Activity
?1.?手動創建 Activity?
- 在 Android Studio 中,右擊包名(如java/com/demo)→ New → Activity → Empty Activity,輸入名稱(如?
MainActivity
),取消勾選自動生成布局文件和主 Activity 選項。 - 自動生成的類需繼承?
AppCompatActivity
,并重寫?onCreate()
?方法:
// java/com/demo/MainActivity.java
package com.demopublic class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);// 初始化組件和布局}@Overrideprotected void onStart() {// Activity 可見但未獲取焦點}@Overrideprotected void onResume() {// 恢復交互,如重啟動畫}@Overrideprotected void onPause() {// 暫停耗時操作,保存臨時數據}@Overrideprotected void onStop() {// 釋放非必要資源}@Overrideprotected void onDestroy() {// 清理線程、關閉數據庫連接和網絡請求、釋放資源,避免內存泄漏}
}
2?.?配置布局文件?
- 在?
res/layout
?目錄新建 XML 文件(如?activity_main.xml
),定義 UI 元素。 - 在 Activity 中通過?
setContentView(R.layout.activity_main)
?加載布局。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"tools:context=".MainActivity"><!-- 頂部標題欄 --><TextViewandroid:id="@+id/tv_title"android:layout_width="match_parent"android:layout_height="60dp"android:gravity="center"android:text="用戶登錄"android:textSize="24sp"android:background="#3F51B5"android:textColor="#FFFFFF"/><!-- 輸入區域 --><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="vertical"android:padding="16dp"><EditTextandroid:id="@+id/et_username"android:layout_width="match_parent"android:layout_height="wrap_content"android:hint="請輸入用戶名"android:inputType="text"/><EditTextandroid:id="@+id/et_password"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginTop="12dp"android:hint="請輸入密碼"android:inputType="textPassword"/><Buttonandroid:id="@+id/btn_login"android:layout_width="match_parent"android:layout_height="48dp"android:layout_marginTop="24dp"android:text="立即登錄"android:onClick="onLoginClick"android:backgroundTint="#2196F3"android:textColor="#FFFFFF"/></LinearLayout><!-- 底部操作區域 --><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="horizontal"android:gravity="center"><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="注冊賬號"android:textColor="#757575"/><Viewandroid:layout_width="1dp"android:layout_height="16dp"android:layout_marginHorizontal="12dp"android:background="#BDBDBD"/><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="忘記密碼"android:textColor="#757575"/></LinearLayout></LinearLayout>
3. 注冊 Activity?
- 在?
AndroidManifest.xml
?中添加聲明:
<activityandroid:name=".MainActivity"android:label="主界面"><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter>
</activity>
三、Activity 跳轉與數據傳遞
1.?顯式 Intent 跳轉
Intent intent = new Intent(MainActivity.this, SecondActivity.class);
intent.putExtra("key", "value"); // 附加數據
startActivity(intent);
2.??隱式 Intent 跳轉
在目標 Activity 的 Manifest 中聲明:
<activity android:name=".SecondActivity"><intent-filter><action android:name="com.demo.action.ACTION_VIEW" /><category android:name="android.intent.category.DEFAULT" /></intent-filter>
</activity>
調用代碼:
Intent intent = new Intent("com.demo.action.ACTION_VIEW");
startActivity(intent);// 或者
Intent intent = new Intent();
intent.setAction("com.demo.action.ACTION_VIEW");
startActivity(intent);
無需在代碼中顯式導入目標 Activity 的包名或類。?
注意事項:
- ?必須包含 DEFAULT category?:隱式 Intent 的接收 Activity 需在?
<intent-filter>
?中聲明?android.intent.category.DEFAULT
,否則會觸發?ActivityNotFoundException
。 - ?自定義 action 命名規范?:如
com.demo.action.ACTION_VIEW
,避免與其他應用沖突。 - ?多應用匹配處理?:若多個應用聲明相同?
action
,系統會彈出選擇器讓用戶選擇目標應用。
3. 返回數據?
使用?startActivityForResult()
?啟動 Activity,并在?onActivityResult()
?處理返回數據。
-
MainActivity發送數據并啟動新的SecondActivity。輸入參數通過?
Intent.putExtra()
?傳遞。
public class MainActivity extends AppCompatActivity {// 自定義請求標識符,用于區分不同Activity的返回結果private static final int REQUEST_CODE = 1001;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);Button btnOpen = findViewById(R.id.btn_open);btnOpen.setOnClickListener(v -> {// 1. 創建顯式 IntentIntent intent = new Intent(MainActivity.this, SecondActivity.class);// 2. 傳遞輸入參數intent.putExtra("username", "admin");intent.putExtra("max_tries", 3);// 3. 啟動并等待返回結果startActivityForResult(intent, REQUEST_CODE);});}// 4. 接收返回結果的回調方法@Overrideprotected void onActivityResult(int requestCode,int resultCode,@Nullable Intent data) {super.onActivityResult(requestCode, resultCode, data);if (requestCode == REQUEST_CODE) { // 匹配SecondActivity的返回結果if (resultCode == RESULT_OK && data != null) {// 5. 解析返回數據String result = data.getStringExtra("result_key");int score = data.getIntExtra("score", 0);// 6. 更新UI(示例:顯示結果)TextView tvResult = findViewById(R.id.tv_result);tvResult.setText("結果: " + result + " 得分: " + score);} else {Toast.makeText(this, "用戶取消操作", Toast.LENGTH_SHORT).show();}}}
}
- SecondActivity接收數據并返回結果。返回數據通過?
setResult()
?返回。
public class SecondActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_second);// 1. 接收輸入參數Bundle extras = getIntent().getExtras();if (extras != null) {String username = extras.getString("username");int maxTries = extras.getInt("max_tries", 1);Log.d("DEBUG", "用戶名: " + username + " 最大嘗試次數: " + maxTries);}Button btnConfirm = findViewById(R.id.btn_confirm);btnConfirm.setOnClickListener(v -> {// 2. 創建返回數據的 IntentIntent resultIntent = new Intent();resultIntent.putExtra("result_key", "操作成功");resultIntent.putExtra("score", 85);// 3. 設置結果碼并結束當前 ActivitysetResult(RESULT_OK, resultIntent);finish();});Button btnCancel = findViewById(R.id.btn_cancel);btnCancel.setOnClickListener(v -> {// 4. 用戶取消操作的處理setResult(RESULT_CANCELED);finish();});}
}
結果碼:
RESULT_OK
:操作成功完成RESULT_CANCELED
:用戶取消操作- 也可自定義數值(需使用?
Activity.RESULT_FIRST_USER
?+ N 格式)
4.?新版 Activity Result API
Google 推薦使用?ActivityResultContracts
?替代傳統方式startActivityForResult():
// 在 Activity/Fragment 中初始化
ActivityResultLauncher<Intent> launcher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(),result -> {if (result.getResultCode() == RESULT_OK) {Intent data = result.getData();// 處理返回數據}}
);// 啟動 Activity
launcher.launch(new Intent(this, SecondActivity.class));
四、數據保存與恢復
1?.?臨時數據保存
屏幕旋轉等場景,需通過?onSaveInstanceState()
?保存數據,并在重建時通過?onCreate()
?或?onRestoreInstanceState()
?恢復。
public class MainActivity extends AppCompatActivity {private static final String KEY_COUNTER = "counter";private static final String KEY_TEXT = "user_input";private static final String KEY_USER = "user_object";private int mCounter = 0;private EditText mEditText;private User mUser; // 假設 User 類實現了 Parcelable@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);mEditText = findViewById(R.id.et_input);// 方式1:通過 onCreate 恢復(推薦)if (savedInstanceState != null) {mCounter = savedInstanceState.getInt(KEY_COUNTER, 0);mEditText.setText(savedInstanceState.getString(KEY_TEXT));mUser = savedInstanceState.getParcelable(KEY_USER);Log.d("RESTORE", "通過onCreate恢復數據");}}// 方式2:通過 onRestoreInstanceState 恢復(可選)@Overrideprotected void onRestoreInstanceState(@NonNull Bundle savedInstanceState) {super.onRestoreInstanceState(savedInstanceState);// 此處的 Bundle 一定非空,無需判空String tempText = savedInstanceState.getString(KEY_TEXT);if (!TextUtils.isEmpty(tempText)) {mEditText.setText(tempText);}Log.d("RESTORE", "通過onRestoreInstanceState恢復數據");}@Overrideprotected void onSaveInstanceState(@NonNull Bundle outState) {super.onSaveInstanceState(outState);// 保存基本類型outState.putInt(KEY_COUNTER, mCounter);// 保存用戶輸入outState.putString(KEY_TEXT, mEditText.getText().toString());// 保存自定義對象(需實現 Parcelable)if (mUser != null) {outState.putParcelable(KEY_USER, mUser);}Log.d("SAVE", "數據已保存");}// 示例按鈕點擊事件public void incrementCounter(View view) {mCounter++;TextView tvCounter = findViewById(R.id.tv_counter);tvCounter.setText(String.valueOf(mCounter));}
}
?2.?持久化數據?
建議在?onPause()
?中執行保存操作。
特性? | SharedPreferences | SQLite |
---|---|---|
?數據類型? | 簡單鍵值對(基本類型、字符串) | 結構化數據(支持復雜查詢) |
?存儲容量? | 適合小數據(KB級) | 適合大數據(MB級) |
?查詢能力? | 無 | 支持SQL查詢、事務、索引 |
?適用場景? | 用戶設置、臨時狀態 | 用戶生成內容、歷史記錄 |
?性能表現? | 讀寫速度快 | 寫操作較慢(需事務優化) |
a. 使用 SharedPreferences 保存數據(適合簡單配置)
public class MainActivity extends AppCompatActivity {private static final String PREFS_NAME = "MyPrefs";private static final String KEY_USERNAME = "username";private static final String KEY_REMEMBER_ME = "remember_me";private EditText etUsername;private CheckBox cbRememberMe;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);etUsername = findViewById(R.id.et_username);cbRememberMe = findViewById(R.id.cb_remember);// 從 SharedPreferences 加載數據SharedPreferences prefs = getSharedPreferences(PREFS_NAME, MODE_PRIVATE);etUsername.setText(prefs.getString(KEY_USERNAME, ""));cbRememberMe.setChecked(prefs.getBoolean(KEY_REMEMBER_ME, false));}@Overrideprotected void onPause() {super.onPause();// 保存數據到 SharedPreferencesSharedPreferences.Editor editor= getSharedPreferences(PREFS_NAME, MODE_PRIVATE).edit();editor.putString(KEY_USERNAME, etUsername.getText().toString());editor.putBoolean(KEY_REMEMBER_ME, cbRememberMe.isChecked());editor.apply(); // 使用異步提交避免阻塞}
}
b. 使用 SQLite 保存數據(適合結構化數據)
數據庫幫助類:
public class UserDbHelper extends SQLiteOpenHelper {private static final String DATABASE_NAME = "UserDatabase.db";private static final int DATABASE_VERSION = 1;// 用戶表結構private static final String SQL_CREATE_ENTRIES ="CREATE TABLE " + UserContract.UserEntry.TABLE_NAME + " (" +UserContract.UserEntry._ID + " INTEGER PRIMARY KEY," +UserContract.UserEntry.COLUMN_NAME + " TEXT," +UserContract.UserEntry.COLUMN_EMAIL + " TEXT)";public UserDbHelper(Context context) {super(context, DATABASE_NAME, null, DATABASE_VERSION);}@Overridepublic void onCreate(SQLiteDatabase db) {db.execSQL(SQL_CREATE_ENTRIES);}@Overridepublic void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {// 簡單示例直接刪除舊表db.execSQL("DROP TABLE IF EXISTS " + UserContract.UserEntry.TABLE_NAME);onCreate(db);}
}
數據操作實現:
public class MainActivity extends AppCompatActivity {private EditText etName, etEmail;private UserDbHelper dbHelper;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);etName = findViewById(R.id.et_name);etEmail = findViewById(R.id.et_email);dbHelper = new UserDbHelper(this);loadDataFromDatabase();}private void loadDataFromDatabase() {SQLiteDatabase db = dbHelper.getReadableDatabase();Cursor cursor = db.query(UserContract.UserEntry.TABLE_NAME,null, null, null, null, null, null);if (cursor.moveToFirst()) {etName.setText(cursor.getString(cursor.getColumnIndex(UserContract.UserEntry.COLUMN_NAME)));etEmail.setText(cursor.getString(cursor.getColumnIndex(UserContract.UserEntry.COLUMN_EMAIL)));}cursor.close();}@Overrideprotected void onPause() {super.onPause();saveToDatabase();}private void saveToDatabase() {SQLiteDatabase db = dbHelper.getWritableDatabase();// 先清空舊數據(根據業務需求決定是否保留歷史)db.delete(UserContract.UserEntry.TABLE_NAME, null, null);ContentValues values = new ContentValues();values.put(UserContract.UserEntry.COLUMN_NAME,etName.getText().toString());values.put(UserContract.UserEntry.COLUMN_EMAIL,etEmail.getText().toString());db.insert(UserContract.UserEntry.TABLE_NAME, null, values);}@Overrideprotected void onDestroy() {dbHelper.close(); // 必須關閉數據庫連接super.onDestroy();}
}
五、Activity 啟動模式
模式? | ?行為描述? | ?典型場景? |
---|---|---|
standard | 默認模式,每次啟動創建新實例入棧,即使已存在相同Activity。 | 普通頁面跳轉,如列表→詳情 |
singleTop | 若目標Activity在棧頂,直接復用,調用onNewIntent()。 | 避免重復推送,如通知欄點擊 |
singleTask | 若棧中存在目標Activity實例,清空其上方所有實例并移至棧頂;否則,新建實例。 | 應用主頁(保證唯一性) |
singleInstance | 獨占新任務棧,全局唯一實例;其他應用調用時直接復用。 | 獨立功能模塊,如系統相機、系統撥號界面 |
?1.?標準模式(默認)
<activity android:name=".DetailActivity" /> <!-- 默認無需顯式聲明 -->
2.?棧頂復用模式
<activity android:name=".NotificationActivity"android:launchMode="singleTop" /> <!-- 避免多次點擊通知重復創建 -->
3.?任務棧內唯一模式
<activity android:name=".MainActivity"android:launchMode="singleTask" /> <!-- 應用主入口 -->
4. 全局單例模式(很少用)
<activity android:name=".CameraActivity"android:launchMode="singleInstance" <!-- 聲明為全局單例模式 -->android:taskAffinity="com.example.camera.task" /> <!-- 指定獨立任務棧(可選) -->
注意:
- 優先級沖突?:若同時通過
Intent
標志(如FLAG_ACTIVITY_NEW_TASK
)設置啟動模式,Intent
標志優先級高于AndroidManifest.xml
配置。 - ?任務棧管理?:
singleTask
和singleInstance
模式會顯著影響任務棧結構,需結合實際業務邏輯設計。
當前主流實踐推薦:?核心頁面(如主頁)使用
singleTask
,高頻復用頁面(如通知頁)使用singleTop
?,以優化內存和用戶體驗。
六、自定義返回行為
基礎自定義返回實現:
public class MainActivity extends AppCompatActivity {private long backPressedTime = 0;@Overridepublic void onBackPressed() {// 場景1:雙擊返回退出應用if (backPressedTime + 2000 > System.currentTimeMillis()) {super.onBackPressed(); // 執行默認返回finishAffinity(); // 關閉所有關聯Activity} else {Toast.makeText(this, "再按一次退出", Toast.LENGTH_SHORT).show();}backPressedTime = System.currentTimeMillis();// 場景2:Fragment返回棧處理if (getSupportFragmentManager().getBackStackEntryCount() > 0) {getSupportFragmentManager().popBackStack();} else {super.onBackPressed(); // 必須調用父類方法}}
}
Android X推薦:
// 在Activity或Fragment中使用
private OnBackPressedCallback callback = new OnBackPressedCallback(true) {@Overridepublic void handleOnBackPressed() {// 自定義返回邏輯if (shouldInterceptBack()) {showExitConfirmation();} else {setEnabled(false); // 禁用當前回調requireActivity().onBackPressed(); // 觸發系統返回}}
};@Override
public void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);// 注冊返回回調(推薦在Fragment中使用)requireActivity().getOnBackPressedDispatcher().addCallback(this, callback);
}
七、復雜界面布局
1. Activity和Fragment
組件 | ?Activity? | ?Fragment? |
---|---|---|
?核心生命周期方法? |
| 包含所有Activity方法,額外增加:
|
?特有方法? | 無 | onAttach() (綁定宿主Activity)onCreateView() (創建UI視圖)onDetach() (解綁宿主Activity) |
?獨立性? | 獨立組件,可直接運行 | 依附于宿主Activity,不可獨立存在 |
?組件定位? | 系統級交互單元(處理權限、窗口管理等) | UI模塊化組件(實現跨Activity界面復用與動態組合) |
2. 典型架構
架構模式? | ?適用場景? | ?優勢? |
---|---|---|
單 Activity 架構 | 復雜導航流程、深度鏈接 | 統一管理導航、更好的狀態恢復 |
多 Activity 架構 | 獨立功能模塊、不同任務棧需求 | 明確職責劃分、方便權限管理 |
混合架構: 單Activity+多Fragment模式? ?多模塊Activity+多Fragment模式?? | 大型項目、模塊化開發 | 靈活組合、便于團隊協作 |