[Android]四大组件简介

在 Android 开发中,“四大组件”(Four Major Components)是指构成 Android 应用程序的四种核心组件,它们通过各自的方式与系统交互,实现应用的多样功能。这些组件是:Activity、Service、Broadcast Receiver 和 Content Provider。每个组件都扮演着不同的角色,并且通过各自的生命周期、方法和目的与 Android 操作系统交互。

一、Activity

在 Android 应用中,Activity 是一个非常核心的组件,用于表示应用的一个单一屏幕,是用户与应用交互的主界面。每个 Activity 提供一个窗口,用于绘制界面和接收与用户的交互事件。理解 Activity 的创建、生命周期和其基本用法对于开发 Android 应用至关重要。

基本概念

一个 Android 应用通常由多个 Activity 组成,每个 Activity 都是一个独立的界面。当你打开一个应用,如邮箱应用,你看到的邮箱列表、邮件详情、写邮件等各个界面,通常都是不同的 Activity

生命周期

Activity 的生命周期是其最重要的特征之一。Android 提供了一系列的回调方法来管理 Activity 的状态,包括用户开始使用 ActivityActivity 进入前台或后台,以及 Activity 被系统销毁的时刻。

下面是 Activity 生命周期的主要方法:

  • onCreate(Bundle savedInstanceState): 当 Activity 被创建时调用。这是初始化界面、成员变量等的地方。
  • onStart(): 当 Activity 对用户可见时调用。
  • onResume(): 当 Activity 准备好与用户交互时调用,此时 Activity 位于前台。
  • onPause(): 当系统即将启动或恢复另一个 Activity 时调用。用于保存数据或释放资源。
  • onStop(): 当 Activity 不再对用户可见时调用。
  • onDestroy(): 当 Activity 即将被销毁时调用。

示例代码

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity

class MainActivity : AppCompatActivity() {
    
    // 当 Activity 被创建时调用
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // 设置 Activity 的布局文件
        setContentView(R.layout.activity_main)

        // 进行初始化操作,比如从 Bundle 恢复数据
        if (savedInstanceState != null) {
            val savedValue = savedInstanceState.getString("key")
            // 使用恢复的数据
        }
    }

    // 当 Activity 开始对用户可见时调用
    override fun onStart() {
        super.onStart()
    }

    // 当 Activity 准备好与用户交互时调用
    override fun onResume() {
        super.onResume()
    }

    // 当 Activity 即将停止与用户交互时调用
    override fun onPause() {
        super.onPause()
        // 保存数据或释放资源
    }

    // 当 Activity 不再完全可见时调用
    override fun onStop() {
        super.onStop()
    }

    // 当 Activity 即将被销毁时调用
    override fun onDestroy() {
        super.onDestroy()
    }

    // 保存 Activity 状态
    override fun onSaveInstanceState(outState: Bundle) {
        super.onSaveInstanceState(outState)
        outState.putString("key", "value")
    }
}

注意事项

  1. 管理资源:由于 Android 设备的资源有限,合理管理 Activity 的资源非常重要。例如,在 onPause() 或 onStop() 中释放那些不需要的资源。
  2. 状态保存与恢复:Android 系统可能因为资源不足等原因随时终止 Activity。因此,在 onSaveInstanceState(Bundle outState) 中保存重要状态,并在 onCreate(Bundle savedInstanceState) 中恢复状态是很重要的。
  3. 用户界面响应:保证 Activity 响应用户的操作,避免在主线程(UI线程)进行耗时操作,这样可以防止应用界面冻结。

二、Service

在 Android 开发中,Service 是一种用于在后台执行长时间运行的任务而不提供用户界面的应用组件。Service 可以在应用的前台或者后台执行任务,即使用户离开了应用。服务是用来处理不需要与用户交互而需要长期运行的操作,例如在后台播放音乐、执行文件下载等。

基本类型

Service 主要有两种形式:

  1. 前台服务(Foreground Service):前台服务显示一个持续的通知,这意味着用户清楚地知道正在运行的服务。这种服务用于用户积极参与的任务(如播放音乐)或对用户很重要的任务(如文件下载)。
  2. 后台服务(Background Service):在应用不在屏幕上显示时执行的服务。从 Android Oreo(8.0)开始,后台服务的运行受到了严格限制以优化应用对设备电池生命的影响。

生命周期方法

Service 有自己的生命周期方法,用于管理其创建、启动、绑定和销毁过程:

  • onCreate(): 服务创建时调用。
  • onStartCommand(Intent intent, int flags, int startId): 每次通过 startService() 方法启动服务时调用。
  • onBind(Intent intent): 当其他组件想要与服务绑定时调用,需要返回一个 IBinder 对象,通过该对象组件可以与服务进行通信。
  • onUnbind(Intent intent): 当所有组件都与服务解除绑定时调用。
  • onDestroy(): 服务销毁之前调用。

示例代码

下面是一个简单的服务示例,该服务在后台记录日志。

import android.app.Service
import android.content.Intent
import android.os.IBinder
import android.util.Log

class MyService : Service() {

    // 当服务被创建时调用
    override fun onCreate() {
        super.onCreate()
        Log.d("MyService", "服务已创建")
    }

    // 每次服务启动时调用
    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        Log.d("MyService", "服务正在运行")
        // 如果我们希望服务在终止后重启,则返回 START_STICKY
        return START_STICKY
    }

    // 当服务被销毁时调用
    override fun onDestroy() {
        super.onDestroy()
        Log.d("MyService", "服务已销毁")
    }

    // 当其他组件想要绑定服务时调用
    override fun onBind(intent: Intent): IBinder? {
        // 本示例不提供绑定功能,因此返回 null
        return null
    }
}

在 AndroidManifest.xml 中注册服务

要使服务能够运行,必须在应用的 AndroidManifest.xml 文件中进行声明:

<application
    ...>
    <service android:name=".MyService" />
</application>

启动和停止服务

你可以从 Activity 或其他组件中启动和停止服务。

val intent = Intent(this, MyService::class.java)
startService(intent)  // 启动服务
stopService(intent)   // 停止服务

注意事项

  • 资源管理:服务可以无限运行,但这可能消耗大量的电池和计算资源。确保服务不会无谓地消耗资源。
  • 服务和线程:服务运行在应用的主线程中,因此如果在服务中执行耗时操作,需要手动创建新线程来处理这些操作,以避免阻塞主线程。
  • 服务的适用场景:在考虑使用服务之前,评估是否真的需要服务。对于简单的、短暂的后台操作,可以考虑使用 WorkManager 或 AlarmManager

三、Broadcast Receiver

在 Android 中,Broadcast Receiver(简称广播接收器)是一个用来处理来自系统或应用发出的广播通知的组件。它可以对诸如设备启动完成、电池电量变化、短信接收等系统事件做出响应,也可以接收应用自定义的广播消息。

基本概念

广播接收器主要用于监听和响应广播消息。广播可以是系统广播(比如网络状态改变、屏幕关闭等),也可以是应用程序发送的广播。广播接收器本身没有用户界面,但它可以启动一个活动或服务来响应接收到的信息。

生命周期和类型

广播接收器不像 Activity 或 Service 那样拥有完整的生命周期。它只有一个回调方法 onReceive(Context context, Intent intent),当接收到广播时被调用。广播接收器的类型分为两种:

  • 静态注册:在 AndroidManifest.xml 中注册。即使应用没有运行,只要事件发生,系统就会创建广播接收器的实例并调用它。
  • 动态注册:在代码中注册,通常在 Activity 或 Service 中注册。它只在其宿主组件(如 Activity)存在时活跃。

示例代码

下面是一个静态注册的广播接收器,用于接收设备启动完成后的广播:

AndroidManifest.xml:

<application ... >
    <receiver android:name=".BootCompletedReceiver">
        <intent-filter>
            <action android:name="android.intent.action.BOOT_COMPLETED" />
        </intent-filter>
    </receiver>
</application>

BootCompletedReceiver.kt:

import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.widget.Toast

class BootCompletedReceiver : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {
        // 确认接收到的是设备启动完成的广播
        if (intent.action == Intent.ACTION_BOOT_COMPLETED) {
            Toast.makeText(context, "设备启动完成!", Toast.LENGTH_LONG).show()
            // 可以在这里启动一个服务或进行其他操作
        }
    }
}

下面是动态注册的广播接收器示例,用于在 Activity 中监听网络变化:

MainActivity.kt:

import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.net.ConnectivityManager
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity

class MainActivity : AppCompatActivity() {
    private lateinit var networkChangeReceiver: BroadcastReceiver

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // 初始化广播接收器
        networkChangeReceiver = object : BroadcastReceiver() {
            override fun onReceive(context: Context, intent: Intent) {
                // 检查网络状态变化
                Toast.makeText(context, "网络状态变化", Toast.LENGTH_SHORT).show()
            }
        }

        // 注册接收器监听网络变化
        IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION).also {
            registerReceiver(networkChangeReceiver, it)
        }
    }

    override fun onDestroy() {
        super.onDestroy()
        // 动态注册的接收器必须要取消注册
        unregisterReceiver(networkChangeReceiver)
    }
}

注意事项

  • 性能和资源管理:广播接收器的 onReceive() 方法应该尽快完成,不要进行任何耗时操作,以免阻塞主线程。若需要执行较长时间的任务,应该启动一个 Service
  • 权限问题:接收某些系统广播可能需要声明相应的权限,比如接收开机广播需要声明 RECEIVE_BOOT_COMPLETED 权限。
  • 条件广播和有序广播:Android 提供了条件广播和有序广播两种方式。有序广播允许多个接收器按顺序接收到同一个广播,每个接收器可以终止广播,防止它传递给其他接收器。

四、Content Provider

在 Android 中,Content Provider 是四大组件之一,用于在不同应用程序之间共享数据。它提供了一种封装数据的方式,并通过一套标准的 API 在应用之间进行数据访问。通过使用 Content Provider,一个应用可以允许其他应用访问其数据,而不需要直接访问底层数据库或文件系统。

基本概念

Content Provider 管理对一个或多个数据源(如 SQLite 数据库)的访问,通过 URI(统一资源标识符)来暴露数据。每个 URI 可以指代 Content Provider 中的数据表或表内的特定数据行。通过这种方式,Content Provider 为数据访问提供了封装,并确保了数据访问的安全性。

核心组件

  • URI: 每个 Content Provider 都通过一个唯一的 authority 来标识,该 authority 与 URI 结合使用,用来找到对应的 Content Provider
  • ContentResolver: 提供了一组 API,允许应用查询或修改由 Content Provider 管理的数据。应用通过调用 ContentResolver 的方法,如 query()insert()delete(), 和 update() 来执行操作。

创建一个 Content Provider

创建一个 Content Provider 通常包括以下几个步骤:

  1. 扩展 ContentProvider 类:
    实现必要的方法:onCreate()query()insert()delete(), 和 update()

  2. 在 AndroidManifest.xml 中声明:
    注册 Content Provider 并定义一个唯一的 authority

  3. 使用 URI 访问数据:
    定义和解析 URI 来访问 Content Provider 管理的数据。

示例代码

下面是一个简单的 Content Provider 实现示例:

MyContentProvider.kt:

import android.content.ContentProvider
import android.content.ContentValues
import android.database.Cursor
import android.net.Uri

class MyContentProvider : ContentProvider() {

    // 初始化内容提供者
    override fun onCreate(): Boolean {
        // 初始化数据源等
        return true
    }

    // 查询数据
    override fun query(
        uri: Uri,
        projection: Array<String>?,
        selection: String?,
        selectionArgs: Array<String>?,
        sortOrder: String?
    ): Cursor? {
        // 根据 uri 查询数据
        return null // 示例中返回 null,实际使用时返回查询结果的 Cursor
    }

    // 插入数据
    override fun insert(uri: Uri, values: ContentValues?): Uri? {
        // 插入数据到数据源
        return null // 示例中返回 null,实际使用时返回新插入数据的 Uri
    }

    // 删除数据
    override fun delete(uri: Uri, selection: String?, selectionArgs: Array<String>?): Int {
        // 根据 uri 和条件删除数据
        return 0 // 示例中返回 0,实际使用时返回被删除的行数
    }

    // 更新数据
    override fun update(
        uri: Uri,
        values: ContentValues?,
        selection: String?,
        selectionArgs: Array<String>?
    ): Int {
        // 根据 uri 更新数据
        return 0 // 示例中返回 0,实际使用时返回被更新的行数
    }

    // 返回 MIME 类型
    override fun getType(uri: Uri): String? {
        // 根据 uri 返回 MIME 类型
        return null
    }
}

AndroidManifest.xml:

<application ... >
    <provider
        android:name=".MyContentProvider"
        android:authorities="com.example.myapp.provider"
        android:exported="true"
    />
</application>
使用 Content Provider

其他应用可以通过 ContentResolver 访问 Content Provider

val contentResolver = getContentResolver()
val uri = Uri.parse("content://com.example.myapp.provider/table_name")
val cursor = contentResolver.query(uri, null, null, null, null)

注意事项

  • 权限管理:确保在 AndroidManifest.xml 中配置合适的权限,以保护数据不被未授权访问。可以通过 android:exported 和 android:permission 控制对 Content Provider 的访问。
  • 线程安全Content Provider 的方法可能会被多个线程同时调用,因此实现时需要考虑线程安全。
  • 性能优化:由于 Content Provider 可能会频繁地进行数据库操作,合理设计和优化数据库访问逻辑非常重要,以避免性能瓶颈。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/597380.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

用 node 写一个命令行工具,全局安装可用

现在&#xff0c;不管是前端项目还是 node 项目&#xff0c;一般都会用 npm 做包管理工具&#xff0c;而 package.json 是其相关的配置信息。 对 node 项目而言&#xff0c;模块导出入口文件由 package.json 的 main 字段指定&#xff0c;而如果是要安装到命令行的工具&#x…

28 - 算术运算指令

---- 整理自B站UP主 踌躇月光 的视频 文章目录 1. ALU改进2. CPU 整体电路3. 程序4. 实验结果 1. ALU改进 此前的 ALU&#xff1a; 改进后的 ALU&#xff1a; 2. CPU 整体电路 3. 程序 # pin.pyMSR 1 MAR 2 MDR 3 RAM 4 IR 5 DST 6 SRC 7 A 8 B 9 C 10 D 11 DI 1…

在.NET架构的Winform项目中引入“异步编程”思想和技术

在.NET架构的Winform项目中引入“异步编程”思想和技术 一、异步编程引入&#xff08;1&#xff09;异步编程引入背景&#xff08;2&#xff09;异步编程程序控制流图&#xff08;3&#xff09;异步编程前置知识&#xff1a; 二、异步编程demo步骤1&#xff1a;步骤2&#xff1…

政安晨:【Keras机器学习示例演绎】(三十八)—— 从零开始的文本分类

目录 简介 设置 加载数据IMDB 电影评论情感分类 准备数据 数据矢量化的两种选择 建立模型 训练模型 在测试集上评估模型 制作端到端模型 政安晨的个人主页&#xff1a;政安晨 欢迎 &#x1f44d;点赞✍评论⭐收藏 收录专栏: TensorFlow与Keras机器学习实战 希望政安晨…

在Linux上使用Selenium驱动Chrome浏览器无头模式

大家好&#xff0c;我们平时在做UI自动化测试的时候&#xff0c;经常会用到Chrome浏览器的无头模式&#xff08;无界面模式&#xff09;&#xff0c;并且将测试代码部署到Linux系统中执行&#xff0c;或者平时我们写个爬虫爬取网站的数据也会使用到&#xff0c;接下来和大家分享…

软考中级-软件设计师(九)数据库技术基础 考点最精简

一、基本概念 1.1数据库与数据库系统 数据&#xff1a;是数据库中存储的基本对象&#xff0c;是描述事物的符号记录 数据库&#xff08;DataBase&#xff0c;DB&#xff09;&#xff1a;是长期存储在计算机内、有组织、可共享的大量数据集合 数据库系统&#xff08;DataBas…

python基础---面向对象相关知识

面向对象 可以把数据以及功能打包为一个整体 类: 名称属性(数据)方法 class Person:def __init__(self, name, age):self.age ageself.name namedef print_info:print(self.name, self.age)定义 #经典类 class Dog1:pass# 新式类 class Dog2(object):pass在python3里面这…

LeetCode-741. 摘樱桃【数组 动态规划 矩阵】

LeetCode-741. 摘樱桃【数组 动态规划 矩阵】 题目描述&#xff1a;解题思路一&#xff1a;动态规划&#xff0c;定推初遍举。解题思路二&#xff1a;倒序循环解题思路三&#xff1a;0 题目描述&#xff1a; 给你一个 n x n 的网格 grid &#xff0c;代表一块樱桃地&#xff0…

VMware虚拟机中Linux系统奔溃,怎么办?

一大早启动虚拟机准备开始工作&#xff0c;却遭遇到Linux系统崩溃&#xff0c;屏幕上显示以下错误提示&#xff1a; 这段文本看起来是来自系统引导时的日志信息&#xff0c;提到了一些关于文件系统的问题和建议。根据这段信息&#xff0c;似乎 /dev/sda1 分区中的文件系统存在一…

红日靶场ATTCK 1通关攻略

环境 拓扑图 VM1 web服务器 win7&#xff08;192.168.22.129&#xff0c;10.10.10.140&#xff09; VM2 win2003&#xff08;10.10.10.135&#xff09; VM3 DC win2008&#xff08;10.10.10.138&#xff09; 环境搭建 win7&#xff1a; 设置内网两张网卡&#xff0c;开启…

SeetaFace6人脸检测C++代码实现Demo

SeetaFace6包含人脸识别的基本能力&#xff1a;人脸检测、关键点定位、人脸识别&#xff0c;同时增加了活体检测、质量评估、年龄性别估计&#xff0c;并且顺应实际应用需求&#xff0c;开放口罩检测以及口罩佩戴场景下的人脸识别模型。 官网地址&#xff1a;https://github.co…

dockerk8s常用知识点

1、什么是docker 容器化和虚拟化对比 ▪开源的应用容器引擎&#xff0c;基于 Go 语言开发 ▪容器是完全使用沙箱机制,容器开销极低 ▪Docker就是容器化技术的代名词 ▪Docker也具备一定虚拟化职能 docker三大核心&#xff1a; Docker Engine: 提供了一个可以用来运行和管…

代码+视频,R语言绘制生存分析模型的时间依赖(相关)性roc曲线和时间依赖(相关)性cindex曲线

ROC曲线分析是用于评估一个因素预测能力的手段&#xff0c;是可以用于连续型变量分组的方法。在生存分析中&#xff0c;疾病状态和因素取值均会随时间发生变化。而标准的ROC曲线分析将个体的疾病状态和因素取值视作固定值&#xff0c;未将时间因素考虑在分析之中。在这种情况下…

edge使用心得

1. **性能提升**&#xff1a;基于Chromium的Edge浏览器在速度和响应方面有显著提升&#xff0c;特别是在处理复杂的网页结构和执行JavaScript代码时。这意味着无论是日常浏览还是运行Web应用程序&#xff0c;都能享受流畅的用户体验。 2. **更好的兼容性**&#xff1a;由于与G…

大模型最新消息

最新消息如下&#xff1a; 大语言模型服务的多样化&#xff1a;互联网上出现了许多免费的大语言模型服务&#xff0c;如OpenAI的ChatGPT、Google的Gemini、Anthropic的Claude、Meta的Llama等。这些服务的推出使得大语言模型的应用更加广泛和便捷。软银和苹果的AI新动向&#x…

​​【收录 Hello 算法】3.3 数字编码

目录 3.3 数字编码 3.3.1 原码、反码和补码 3.3.2 浮点数编码 3.3 数字编码 Tip 在本书中&#xff0c;标题带有 * 符号的是选读章节。如果你时间有限或感到理解困难&#xff0c;可以先跳过&#xff0c;等学完必读章节后再单独攻克。 3.3.1 原码、反码和补码 在…

迅睿CMS中实现关键词搜索高亮

在迅睿CMS系统中实现关键词搜索高亮是提升用户体验和搜索效果的重要手段。当用户搜索某个关键词时&#xff0c;将搜索结果中的关键词高亮显示&#xff0c;可以帮助用户更快速地定位到所需信息。 关键词高亮的实现 在迅睿CMS中&#xff0c;你可以使用内置的dr_keyword_highlig…

Study--Oracle-01-单实例部署Oracle11G-R2

Oracle版本发布介绍 Oracle 19c和12c和11g功能区别_数据库_oracle_支持 一、CentOS 7 环境准备 1、软件准备 操作系统&#xff1a;CentOS 7 数据库版本: Oracle11g R2 2、操作系统环境配置 关闭selinux &#xff0c;编辑 /etc/selinux/config文件&#xff0c;设置SELINU…

C语言例题34、反向输出字符串(递归方式)

题目要求&#xff1a;输入5个字符后&#xff0c;使用递归方式逆序输出 #include <stdio.h>void reverse(int num) {char cur_char;if (num 1) {cur_char getchar();printf("逆序输出为&#xff1a;");putchar(cur_char);} else {cur_char getchar();revers…

宏电全栈式IoT赋能供排水智能监测,护航城市生命线

城市供水、排水系统是维系城市正常运行、满足群众生产生活需要的重要基础设施&#xff0c;是城市的“生命线”。随着城市化进程加快&#xff0c;城市规模不断扩大&#xff0c;地下管线增长迅速&#xff0c;城市“生命线安全”的监管日益面临挑战。 宏电作为物联网行业的领航者…