目录
一、什么是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模式 | 大型项目、模块化开发 | 灵活组合、便于团队协作 |