当前位置: 首页 > news >正文

【Android】四大组件之Activity

目录

一、什么是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() 中执行保存操作。

特性SharedPreferencesSQLite
数据类型简单键值对(基本类型、字符串)结构化数据(支持复杂查询)
存储容量适合小数据(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配置。
  • 任务栈管理‌:singleTasksingleInstance模式会显著影响任务栈结构,需结合实际业务逻辑设计。

当前主流实践推荐:‌核心页面(如主页)使用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

    组件ActivityFragment
    核心生命周期方法

    onCreate() 

    onStart() 

    onResume()

    onPause()

    onStop() 

    onDestroy()

    包含所有Activity方法,额外增加:
    onAttach()

    onCreateView()

    onDestroyView()

    onDetach()

    特有方法onAttach()(绑定宿主Activity)
    onCreateView()(创建UI视图)
    onDetach()(解绑宿主Activity)
    独立性独立组件,可直接运行依附于宿主Activity,不可独立存在
    组件定位系统级交互单元(处理权限、窗口管理等)UI模块化组件(实现跨Activity界面复用与动态组合)

    2. 典型架构

    架构模式适用场景优势
    单 Activity 架构复杂导航流程、深度链接统一管理导航、更好的状态恢复
    多 Activity 架构独立功能模块、不同任务栈需求明确职责划分、方便权限管理

    混合架构:

    单Activity+多Fragment模式

    多模块Activity+多Fragment模式‌ 

    大型项目、模块化开发灵活组合、便于团队协作

    相关文章:

  • Java 中 ConcurrentHashMap 1.7 和 1.8 之间有哪些区别?
  • 【补题】Codeforces Global Round 20 F1. Array Shuffling
  • Unity-Shader详解-其一
  • LabVIEW 工业产线开发要点说明
  • 深入理解TransmittableThreadLocal:原理、使用与避坑指南
  • 职业教育新形态数字教材的建设与应用:重构教育生态的数字化革命
  • html初识
  • 【JavaScript】自增和自减、逻辑运算符
  • LeetCode热题100——70. 爬楼梯
  • SQL盲注问题深度解析与防范策略
  • Python 第 11 节课 - string 与 random 的方法
  • 《Vue3学习手记5》
  • 科学养生,开启健康生活新方式
  • 【Flume 】Windows安装步骤、配置环境
  • 深度解析责任链Filter模式:构建灵活可扩展的请求处理管道
  • ngrok 内网穿透技术系统性文档
  • MES系列-MOM(Manufacturing Operations Management,制造运营管理)
  • Eclipse 插件开发 2
  • 深入解析Dify中的文本清洗处理器:CleanProcessor详解
  • NSIS打包
  • 我国对国家发展规划专门立法
  • 知名计算机专家、浙江大学教授张森逝世
  • 又一名90后干部被查,已有多人倒在乡镇领导岗位上
  • 特朗普承认“24小时结束俄乌冲突”是玩笑:大家都知道
  • 永辉超市一季度净利降近八成,未来12个月至18个月是改革成果集中释放期
  • 铜钴巨头洛阳钼业一季度净利润同比大增九成,最新宣布超30亿元收购黄金资产