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

【Android】初识 Activity

文章目录

  • 初识 Activity
    • 1. Activity 是什么?
    • 2. 如何创建 Activity?
      • 2.1 新建一个类继承 Activity 类或其子类
      • 2.2 在 AndroidManifeat 文件中注册
      • 2.3 创建和加载布局
    • 3. Activity 间跳转与传递数据
      • 3.1 使用显示 Intent
      • 3.2 使用隐式 Intent
      • 3.3 向下一个活动传递数据
      • 3.4 返回数据给上一个活动
      • 3.5 小结

初识 Activity

1. Activity 是什么?

Android 的 Activity 是构建用户界面的基本单元,它代表了一个独立的交互屏幕。可以理解为:Activity = 应用中的一个“窗口”。

它解决了移动应用用户入口点不确定的问题,因为任何 Activity 都可以作为应用的入口。应用由多个松散耦合的 Activity 组成,共同协作完成用户任务。一个 Activity 可以启动自己应用内的其他 Activity,甚至可以启动其他应用的 Activity。

要使用 Activity,开发者必须:

  • 在 AndroidManifest.xml 中声明它们;
  • 正确实现其生命周期回调方法来管理资源和状态。

Activity 提供了应用绘制 UI 的窗口,是用户与应用交互的核心组件。

参考:activity 简介 | Android Developers

2. 如何创建 Activity?

一般当我们创建一个新项目的时候,Android Studio 会帮我们创建一个 MainActivity,如果我们还想创建新的 Activity,最简单的方式是直接通过 Android Studio 直接 new 一个 Activity。但还是得了解 Activity 具体的创建过程。

手动创建主要有三步:

2.1 新建一个类继承 Activity 类或其子类

所有活动都必须继承某个 Activity 类,例如下面这段代码继承了 AppCompatActivity 类,这是 Activity 的子类。

public class TestActivity extends AppCompatActivity {@Overrideprotected void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);}
}

项目中任何活动都应重写 Activity 中的 onCreate() 方法,这里的 onCreate() 方法非常简单,就是调用了父类的 onCreate() 方法。当然这里只是默认的实现,后面还需要在这里面加入很多自己的逻辑。

2.2 在 AndroidManifeat 文件中注册

所有的活动都要在 AndroidManifest.xml 中注册才能生效,打开 app/src/main/AndroidManifest.xml,可以找到类似下面这段代码:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"><applicationandroid:allowBackup="true"android:dataExtractionRules="@xml/data_extraction_rules"android:fullBackupContent="@xml/backup_rules"android:icon="@mipmap/ic_launcher"android:label="@string/app_name"android:roundIcon="@mipmap/ic_launcher_round"android:supportsRtl="true"android:theme="@style/Theme.HelloWorld"tools:targetApi="31"><activityandroid:name=".MainActivity"android:exported="true"><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter></activity></application></manifest>

需要在 <application> ... </application> 标签内部,添加新的 <activity> 标签

<applicationandroid:allowBackup="true"android:dataExtractionRules="@xml/data_extraction_rules"android:fullBackupContent="@xml/backup_rules"android:icon="@mipmap/ic_launcher"android:label="@string/app_name"android:roundIcon="@mipmap/ic_launcher_round"android:supportsRtl="true"android:theme="@style/Theme.HelloWorld"tools:targetApi="31"><!-- 注册新添加的 SecondActivity --><activity android:name=".TestActivity" android:exported="false" /><!-- 启动入口 MainActivity --><activityandroid:name=".MainActivity"android:exported="true"><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter></activity>
</application>

android:name

  • .TestActivity:表示类名是 TestActivity,位于主包(com.example.xxx)下;

  • 如果类在子包中(比如 ui.TestActivity),就写成:

    android:name=".ui.TestActivity"
    

android:exported

  • 必须显式写明(从 Android 12(API 31)开始强制要求);
  • 含义:
    • true:这个 Activity 可以被外部(如系统、其他 App)启动;
    • false:只能被你自己 App 内部启动;
  • 一般只有intent-filter 的 Activity需要设为 true(比如 MainActivity 是启动入口),其他默认写 false 即可。

如果想将这个活动设置成主活动,只需添加如下 intent-filter 标签:

<activity android:name=".SecondActivity" android:exported="true"><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter>
</activity>

需要注意这里android:exported必须设为true

2.3 创建和加载布局

Android 程序的设计讲究逻辑和视图分离,最好每一个活动都能一个布局,布局就是用来显示界面内容的,新建一个布局,可以看到如下代码:

<?xml version="1.0" encoding="utf-8"?>    <androidx.constraintlayout.widget.ConstraintLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"></androidx.constraintlayout.widget.ConstraintLayout>
  • <?xml version="1.0" encoding="utf-8"?>

    这行属于 XML 标准声明,目的是告诉解析器文件使用的是哪种 XML 版本和编码。必须写在布局文件最开头,否则 Android Studio 无法正确解析。

  • <androidx.constraintlayout.widget.ConstraintLayout ...>

    根布局使用ConstraintLayout,根布局就是界面的“父容器”,负责托住所有控件,并决定它们的排列方式和界面基础样式。每个 XML 布局文件必须有且只能有一个根布局

  • xmlns:android="http://schemas.android.com/apk/res/android"

    这是 XML 命名空间声明xmlns 是 “XML namespace” 的缩写,含义是:“我下面所有的 android: 属性都来自这个命名空间”。

  • android:layout_widthandroid:layout_height 控制控件的大小行为,是每个控件布局时必须设置的两个核心属性。

对上面代码进行编辑:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"  android:layout_width="match_parent"android:layout_height="match_parent"><Buttonandroid:id="@+id/btn_click_me"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="点我"app:layout_constraintTop_toTopOf="parent"app:layout_constraintStart_toStartOf="parent" /></androidx.constraintlayout.widget.ConstraintLayout>

这里添加了一个 Button 元素,也就是加了个按钮,创建完布局后,接下来就可以在活动中加载这个布局了。

public class TestActivity extends AppCompatActivity {@Overrideprotected void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.test_layout);}
}

这里调用了 setContentView() 方法来给当前活动加载一个布局,在这个方法中,一般会传入一个布局文件的 id 。项目中添加的任何资源都会在 R 文件中生成一个相应的资源 id,可通过 R.layout.test_layout 进行访问。

3. Activity 间跳转与传递数据

准备工作:新建MainActivity 和 SecondActivity,将 MainActivity 设为主活动,在 layout 目录下修改他们的布局文件,代码如下:

<!--    activity_main.xml    -->
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:id="@+id/main"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivity"><Buttonandroid:id="@+id/button"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="跳转到 SecondActivity"app:layout_constraintTop_toTopOf="parent"app:layout_constraintStart_toStartOf="parent"android:layout_marginTop="0dp"android:layout_marginStart="0dp" /></androidx.constraintlayout.widget.ConstraintLayout>
<!--    activity_second.xml    -->
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:id="@+id/main"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".SecondActivity"><TextViewandroid:id="@+id/textView"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="这里是 SecondActivity"app:layout_constraintTop_toTopOf="parent"app:layout_constraintStart_toStartOf="parent"android:layout_marginTop="0dp"android:layout_marginStart="0dp"/></androidx.constraintlayout.widget.ConstraintLayout>
<!--    AndroidManifest.xml    -->
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools" ><applicationandroid:allowBackup="true"android:dataExtractionRules="@xml/data_extraction_rules"android:fullBackupContent="@xml/backup_rules"android:icon="@mipmap/ic_launcher"android:label="@string/app_name"android:roundIcon="@mipmap/ic_launcher_round"android:supportsRtl="true"android:theme="@style/Theme.IntentTest"tools:targetApi="31" ><activityandroid:name=".SecondActivity"android:exported="false" /><activityandroid:name=".MainActivity"android:exported="true" ><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter></activity></application></manifest>

第一个活动添加了一个按钮,第二个活动有一个视图。

要实现活动间的跳转,需要用到 Intent,这是 Android 程序中各组件之间交互的一种重要方式,它不仅可以指明当前组件想要执行的动作,还可以在不同组件之间传递数据。Intent 大致可分为两种:显示 Intent隐式 Intent

3.1 使用显示 Intent

明确指定目标 Activity 的类名,用于同一应用内的跳转。

// 在 MainActivity 中启动 SecondActivity
Intent intent = new Intent(MainActivity.this, SecondActivity.class);
startActivity(intent);

首先创建一个 Intent 对象,这里的两个参数:MainActivity.this是当前活动自身的对象(实例),表示当前 Activity 的上下文(Context);SecondActivity.class是目标页面的类,表示想要跳转到的活动。

startActivity(Intent intent)Android 中启动一个新 Activity 的方法,它属于 Context 类(Activity 继承自 Context),用来根据传入的 Intent 打开一个新的页面。系统会根据 Intent 里指定的目标类(或者动作)创建新的 Activity 实例,并把它显示出来。

MainActivity 完整代码如下:

public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);EdgeToEdge.enable(this);setContentView(R.layout.activity_main);ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);return insets;});Button button = findViewById(R.id.button);button.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Intent intent = new Intent(MainActivity.this, SecondActivity.class);startActivity(intent);}});}
}

Button button = findViewById(R.id.button);

  • findViewById 是 Activity 提供的方法,用于根据布局文件中控件的 id 找到对应的控件实例。
  • R.id.button 是资源 ID,指向你在 XML 布局里定义的 <Button android:id="@+id/button" ... />

button.setOnClickListener(new View.OnClickListener() {

  • 给按钮 button 设置一个“监听器”,监听用户的点击行为。
  • setOnClickListener 要传入一个实现了 View.OnClickListener 接口的对象。
  • 这里用的是匿名内部类,直接写一个新的 OnClickListener 对象,简洁方便。

public void onClick(View v) {

  • onClick 是点击事件被触发时调用的回调方法。
  • 参数 View v 是被点击的控件对象(这里就是刚才的按钮)。
  • 当用户点击按钮时,这个方法里的代码就会执行。

运行程序,结果如下图所示:

请添加图片描述

点击按钮

请添加图片描述

3.2 使用隐式 Intent

不直接指定启动组件的意图,而是声明一系列的动作(action)和类别(category),由系统解析这些信息来找到合适的组件进行启动。这种方式的好处是可以使应用更加灵活,不需要知道具体的组件名称,只需知道它能处理的动作类型。

要使用隐式 Intent,首先需要在AndroidManifest.xml中为目标活动配置相应的<intent-filter>。例如,如果想让 SecondActivity 响应一个特定的动作,可以这样配置:

<activityandroid:name=".SecondActivity"android:exported="false"><intent-filter><action android:name="com.example.activitytest.ACTION_START"/><category android:name="android.intent.category.DEFAULT"/></intent-filter>
</activity>

<action>标签中指明了当前活动可以响应 com.example.activitytest.ACTION_START这个 action,而<category>标签包含了附加信息,用来更精确地指明活动能够响应的 Intent 中可能带有的 category。只有当 Intent 中指定的 action 和 category 同时匹配时,活动才能响应该 Intent。

修改 MainActivity 中的代码:

button.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Intent intent = new Intent("com.example.activitest.ACTION_START");startActivity(intent);}
});

运行程序,效果和上面一样。

每个 Intent 只能指定一个 action,但可以指定多个 category。目前这个程序只有一个默认的 category,我们还可以添加自定义 category,代码如下:

button.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Intent intent = new Intent("com.example.activitest.ACTION_START");intent.addCategory("com.example.activitytest.MY_CATEGORY");startActivity(intent);}
});

此时运行程序,点击按钮后程序会直接崩溃。因为我们新增了一个 category 但是 SecondActivity 并没有声明可以响应这个,添加声明后运行程序就恢复正常了。

<activityandroid:name=".SecondActivity"android:exported="false"><intent-filter><action android:name="com.example.activitytest.ACTION_START"/><category android:name="android.intent.category.DEFAULT"/><category android:name="com.example.activitytest.MY_CATEGORY"/></intent-filter>
</activity>

使用隐式 Intent,不仅可以启动自己程序内的活动,还可以启动其他程序内的活动。

例如修改 MainActivity 中代码:

button.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Intent intent = new Intent(Intent.ACTION_VIEW);intent.setData(Uri.parse("http://www.baidu.com"));startActivity(intent);}
});

Intent.ACTION_VIEW 是一个系统内置的 动作常量(action),意思是:“我想查看某个东西”。但这时我们还没有告诉它“查看什么”,需要通过 setData() 设置具体的内容。Uri.parse(...) 会把字符串转为 Uri 类型。启动这个隐式 Intent,Android 系统会去找一个能处理“查看网页”这个动作的组件(通常是浏览器)。然后跳转到那个浏览器界面,加载网页。

重新运行程序,点击按钮,就能看到打开了系统浏览器。

请添加图片描述

3.3 向下一个活动传递数据

在启动活动时传递数据的思路很简单,Intent 中提供了一系列 putExtra() 方法的重载,可以把我们想要传递的数据暂存在 Intent 中,启动另一个活动后,只需要把这些数据从 Intent 中取出即可。例如下面这段代码:

button.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {String data = "Hello SecondActivity";Intent intent = new Intent(MainActivity.this, SecondActivity.class);intent.putExtra("extra_data", data);startActivity(intent);}
});

这里使用显示 Intent 的方式来启动 SecondActivity,并通过 putExtra() 方法传递了一个字符串。

putExtra(String key, String value):给 Intent 添加一个附加信息(键值对)。"extra_data" 是键,data 是值(这里是 "Hello SecondActivity")。本质上是把数据附加到 Intent 上,让目标页面接收。这个数据会被打包进 Intent,随跳转一起传给 SecondActivity

然后我们在 SecondActivity 中将传递的数据取出,代码如下:

Intent intent = getIntent();    // 获取传入的 Intent
String data = intent.getStringExtra("extra_data");    //  通过 key 获取字符串

当然除了字符串,其他数据类型也能传递:

/*    发送方(MainActivity)    */
Intent intent = new Intent(MainActivity.this, SecondActivity.class);
intent.putExtra("int_data", 123);                 // int
intent.putExtra("boolean_data", true);            // boolean
intent.putExtra("double_data", 3.14);             // double
intent.putExtra("string_data", "Hello");          // String
// 数组
intent.putExtra("string_array", new String[] {"A", "B", "C"}); 
intent.putExtra("int_array", new int[] {1, 2, 3});
// 集合(ArrayList)
ArrayList<String> list = new ArrayList<>();
list.add("One");
list.add("Two");
intent.putStringArrayListExtra("string_list", list);
startActivity(intent);
/*    接收方(SecondActivity)    */
Intent intent = getIntent();
int intData = intent.getIntExtra("int_data", 0);
boolean boolData = intent.getBooleanExtra("boolean_data", false);
double doubleData = intent.getDoubleExtra("double_data", 0.0);
String stringData = intent.getStringExtra("string_data");
String[] strArray = intent.getStringArrayExtra("string_array");
int[] intArray = intent.getIntArrayExtra("int_array");
ArrayList<String> list = intent.getStringArrayListExtra("string_list");

3.4 返回数据给上一个活动

这里还是用书上旧版写法,之后再对新版进行学习。

修改 MainActivity 中的代码如下:

// 定义一个请求码,标识是谁发出的请求
private static final int REQUEST_CODE = 1;...button.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Intent intent = new Intent(MainActivity.this, SecondActivity.class);startActivityForResult(intent, REQUEST_CODE);}
});

private static final int REQUEST_CODE = 1;

  • 定义了一个常量 REQUEST_CODE,数值为 1。
  • 这个叫“请求码”,用于 标记是谁发出的请求,方便多个页面跳转时区分来源。

startActivityForResult(intent, REQUEST_CODE);

  • 第一个参数是一个 Intent 对象,用来描述你想启动哪个 Activity,或者你想执行什么操作。
  • 第二个参数是一个整型请求码,自定义的数字,代表“你是谁发起的请求”。当跳转多个 Activity,并都期望返回结果时,系统就通过这个请求码来帮你区分是哪一个请求返回的数据。

SecondActivity 中代码如下:

Button backButton = findViewById(R.id.back_button);
button.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Intent intent = new Intent();intent.putExtra("return_data", "我是 SecondActivity 返回的值");setResult(RESULT_OK, intent);  // 设置返回结果finish(); // 结束当前页面}
});

setResult(RESULT_OK, intent);这句代码告诉系统:当前页面即将结束,并带着一份结果数据返回给上一个页面。

  • RESULT_OK 常量值 -1 ,表示返回成功(操作成功),常见值还包括:
    • RESULT_CANCELED常量值 0,表示取消操作或未完成,默认值,不需要调用 setResult() 也会返回这个;
    • RESULT_FIRST_USER常量值 1,自定义的返回码必须从这个值起,避免和系统定义冲突。
  • 第二个参数是携带数据的 Intent对象。

finish()

  • 关闭当前 Activity(SecondActivity),系统会自动回到之前的 Activity(MainActivity)。
  • 同时,MainActivity 的 onActivityResult() 方法会被调用,并收到你通过 setResult() 设置的 Intent 和结果码。

使用 setActivityForResult() 方法启动 SecondActivity 活动,在 SecondActivity 被销毁后会回调上一个活动的 onActivityResult() 方法,因此需要在 MainActivity 中重写该方法来获取返回数据。代码如下:

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {super.onActivityResult(requestCode, resultCode, data);if (requestCode == REQUEST_CODE && resultCode == RESULT_OK) {String returnedData = data.getStringExtra("return_data");Toast.makeText(this, "返回值:" + returnedData, Toast.LENGTH_SHORT).show();}
}

if (requestCode == REQUEST_CODE && resultCode == RESULT_OK)

  • requestCode是之前 startActivityForResult(intent, REQUEST_CODE) 传入的编号。用它来确认“是我发出的请求”;
  • resultCode是目标页面通过 setResult(RESULT_OK) 返回的结果码。确认结果是“成功”的。
  • 先判断是谁发出的请求、是否成功,再处理数据。

Toast.makeText(this, "返回值:" + returnedData, Toast.LENGTH_SHORT).show();

  • 弹出一个 Toast(短时间提示框);
  • 显示的内容是:"返回值:" + returnedData
  • 举例:如果返回的是 "Hello",就显示返回值:Hello
  • this 是上下文,Toast.LENGTH_SHORT 表示显示时间短。

3.5 小结

Intent 是 Android 中用于“意图”表达的对象,主要用于启动组件(四大组件:Activity(活动)、Service(服务)、BroadcastReceiver(广播) 和 ContentProvider(内容提供器))和传递数据。上面只是简单介绍了一些简单使用,还有很多用法后续深入学习后会专门写一篇关于 Intent 的文章。

相关文章:

  • 【人工智能基础】初识神经网络
  • docker私有仓库部署配置学习
  • 冯·诺依曼体系、哈佛架构以及现代计算机架构中的关键优化技术(多级缓存、流水线)
  • 网络资源模板--基于Android Studio 实现的咖啡点餐App
  • 为什么用Qwen3 embedding和rerank
  • 大模型MetaGPT面试题汇总及参考答案
  • WebRTC(七):媒体能力协商
  • Linux系统之grub-mkstandalone详解
  • C#Halcon从零开发_Day14_AOI缺陷检测策略1_Bolb分析+特征分析
  • 日语学习-日语知识点小记-进阶-JLPT-真题训练-N2阶段(3):单词2018年12月2024年7月
  • 【机器学习四大核心任务类型详解】分类、回归、聚类、降维智能决策指南
  • 案例:塔能科技以“数字光网”重塑某市照明绿色生态
  • rknn优化教程(三)
  • DAY 39 图像数据与显存
  • unity版本控制PlasticSCM转git
  • RADIUS认证服务器全面解析:核心功能、应用场景
  • FLTK从源码编译到使用
  • SQL Server基础语句4:数据定义
  • ROS 2 中 Astra Pro 相机与 YOLOv5 检测功能编译启动全记录
  • 深入解析域名解析API:从gethostbyname到getaddrinfo的演进之路
  • 怎么做自己的简历网站/十大计算机培训机构排名
  • 一诺建站/手机优化软件
  • 企业安全文化建设方案/吉安seo
  • 成都高端网站开发/2345浏览器影视大全
  • wordpress 获取网站地址/交换链接营销实现方式解读
  • 抖音官网链接网站怎么做/企业网站官网