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

移动应用开发期末复习

在这里插入图片描述


目录

    • 题型
    • 第一章 项目结构与配置
      • 安卓项目结构文件夹
      • 清单文件的功能
      • Intent
    • 第二章 Android四大组件
      • Activity
        • 生命周期方法
        • 启动模式
        • 状态保存
        • 跳转与数据传递
      • Service
        • 生命周期
        • 启动方式
        • 绑定服务
      • BroadcastReceiver
        • 类型
        • 注册方式
        • 自定义广播实现
        • 代码实践
      • ContentProvider
        • 内容URI结构
        • 访问数据的组件
        • MIME类型格式getType()
        • 通配符
    • 第三章 通知与后台任务
      • 通知机制
        • 创建通知渠道
        • 通知构建
      • 多媒体处理
        • 音频播放
        • 视频播放
    • 第四章 数据存储与通信
      • SharedPreferences
        • 数据存取流程
        • 文件存储
      • SQLite
        • SQLiteOpenHelper
        • SQLiteDatabase
        • 数据库操作
      • 网络与数据格式
        • JSON与XML对比
        • JSON解析库
    • 第五章 UI开发
      • 常用组件/控件
        • 显示类
        • 输入类
        • 多媒体类
        • 布局容器
          • Fragment
            • Fragment状态
            • 动态加载Fragment
            • 平板大尺寸
          • LinearLayout(水平/垂直)
      • 属性与操作
        • 文本属性
        • 图片资源引用
        • 动态替换Fragment
      • 布局管理
        • 适配不同屏幕
        • LinearLayout特性
    • 题目
      • 选择题
      • 简答题(4题、20分)
        • Android基础入门
        • Android常见页面布局
        • Android常见界面控件
        • 程序活动单元Activity
        • 广播机制
        • 服务
        • 简述Android数据存储的方式
        • 使用内容提供者共享数据
      • 共用选项题(2大题,2分/小题,共20分)
      • 综合题(10分)
    • 2025.6.5考试


题型

  1. 单选题:15题、30分
  2. 多选题:10题、20分 全对满分,少选得半分,选错不得分
  3. 共用选项题:2大题,2分/小题,共20分
  4. 简答题:4题、20分
  5. 综合题:10分
    在这里插入图片描述

第一章 项目结构与配置

基于Linux内核
在这里插入图片描述

安卓的体系结构
Android是一种基于Linux的软件平台和操作系统,采用了软件堆层(Software Stack)的架构,由下往上分别是Linux内核层、硬件抽象层、系统运行时库层(又称为中间件层)、应用程序框架层和系统应用层。
在这里插入图片描述

安卓程序打包发布到应用商店,所用的扩展名是 .apk

AndroidStudio依赖于gdksdk(软件开发包)。


Android应用开发特色

  • 四大组件:Activity、Service、BroadcastReceiver、ContentProvider
  • 丰富的系统控件
  • SQLite数据库:轻量级、运算速度极快的嵌入式关系型数据库。支持SQL语法,还可通过Android封装好的API进行操作。
  • 强大的多媒体:如音乐、视频、录音、拍照等。
  • 可以部署机器学习(深度学习)模型:TensorFLow Lite或PyTorch(ONNX Runtime for Android)

四大组件

  • Activity
  • Service
  • BroadcastReceiver
  • ContentProvider

安卓项目结构文件夹

在这里插入图片描述

  • app: 项目中的代码、资源等内容几乎都是放置在这个目录下的。
  • .gitignore: 这个文件是用来将指定的目录或文件排除在版本控制之外的。
  • build.gradle: 这是项目全局的gradle构建脚本,通常这个文件中的内容是不需要修改的。
  • gradle.properties: 这个文件是全局的gradle配置文件,在这里配置的属性将会影响到项目中所有的gradle编译脚本。
  • gradlew和gradlew.bat: 这两个文件是用来在命令行界面中执行gradle命令的,其中gradlew是在Linux或Mac系统中使用的,gradlew.bat是在Windows系统中使用的。
  • local.properties: 这个文件用于指定本机中的Android SDK路径,通常内容都是自动生成的,我们并不需要修改。
  • settings.gradle: 这个文件用于指定项目中所有引入的模块。
    在这里插入图片描述
  • libs: 如果你的项目中使用到了第三方jar包,就需要把这些jar包都放在libs目录下,放在这个目录下的jar包都会被自动添加到构建路径里去。
  • java: java目录是放置我们所有Java代码的地方(Kotlin代码也是放在这里),展开该目录,你将看到系统帮我们自动生成了一个MainActivity文件。
  • res: 项目中使用到的所有图片、布局、字符串等资源都存放在这个目录下。
  • AndroidManifest.xml: 这是整个Android项目的配置文件。
  • build.gradle: 这是app模块的gradle构建脚本,这个文件中会指定很多项目构建相
    关的配置。
    在这里插入图片描述
  • drawable开头的目录都是用来放图片的。
  • mipmap开头的目录都是用来放应用图标的。
  • values开头的目录都是用来放字符串、样式、颜色等配置的。
  • layout开头的目录都是用来放布局文件的。

安卓系统中定义的单位
在这里插入图片描述
在这里插入图片描述
分析app/build.gradle文件
在这里插入图片描述
在这里插入图片描述
日志工具的使用
在这里插入图片描述

清单文件的功能

清单文件的功能:

  • 注册组件
  • 权限声明
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

Intent

跳转与数据传递

第二章 Android四大组件

Activity

生命周期方法

onCreate
onStart
onResume
onPause
onStop
onDestroy
onRestart

15-认识Android中Activity的生命周期
在这里插入图片描述
在这里插入图片描述

启动模式

Activity-四种启动模式详解
4种启动模式:

  • standard
  • singleTop
  • singleTask
  • singleInstance

返回栈(任务栈)
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

activty4种启动模式:
standard:每启动一个activty都会在返回栈顶创建一个新的示例;
singleTop:启动activity时先判断要启动的activity实例是否位于栈顶,位于栈顶就复用,不在栈顶就创建一个新的实例;
singleTask:启动activity时先判断当前栈中是否有该activity,有就直接复用,并把该activity上的实例全部出栈;
singleInstance:启动activity时,会启动一个新的任务栈管理该activity实例。

📚
在这里插入图片描述

在这里插入图片描述

状态保存

onSaveInstanceState
在这里插入图片描述

跳转与数据传递

显式Intent
隐式Intent
putExtra
16.1-Android中Activity之间的跳转1–显式跳转

显式Intent
在这里插入图片描述
在这里插入图片描述

隐式Intent
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

可选是指设置intent的时可选的,设置过滤条件的时候时必选的。

在这里插入图片描述
在这里插入图片描述

老师ppt:
在这里插入图片描述
显示Intent
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

为按钮 button1 设置点击事件监听器。当用户点击按钮时,会执行大括号内的代码。
创建一个 Intent 对象,指定其动作为 ACTION_VIEW(系统预定义的 “查看” 操作)。
设置意图的数据为百度的 URL。Uri.parse() 将字符串 URL 转换为 Uri 对象(Android 处理统一资源标识符的标准格式)。
启动意图,触发系统查找能够处理该 URL 的应用(通常是浏览器)。

在这里插入图片描述

  • android:name=“.SecondActivity”
    指定 Activity 的类名(完整路径为com.example.ch3_activitytest.SecondActivity)。
  • android:exported=“true”
    声明该 Activity 可被其他应用启动。若设为 false,则只能被当前应用内部的组件调用。
  • <action …>
    定义一个自定义 Action(com.example.ch3_activitytest.ACTION_START)。其他应用可通过该 Action 隐式启动 SecondActivity。
  • <category …>
    添加 DEFAULT 类别,表示该 Activity 支持处理默认的隐式 Intent。若无此类别,无法通过隐式 Intent 启动该 Activity
    在这里插入图片描述
    Action 决定 “做什么”,Category 决定 “在什么场景下做” 或 “由谁来做”。两者结合才能让 Intent 精准匹配到目标组件,既避免误匹配,又能满足安全和业务需求。

自己总结:
1、显示直接写你要启动哪个,一般用启动本应用中的Activity之间的数据
2、隐式根据类别 数据等匹配启动,常见于启动系统中的某些特定的动作,比如打电话.
在这里插入图片描述
为什么有了 Action 还需要 Category?
在这里插入图片描述
一句话总结:Action 决定 “做什么”,Category 决定 “在什么场景下做” 或 “由谁来做”。

🍊
创建intent

val intent = Intent("com.example.ACTION_SHOW")  // 设置 Action
intent.addCategory(Intent.CATEGORY_DEFAULT)     // 添加系统默认 Category
intent.addCategory("com.example.CATEGORY_PRIVATE")  // 添加自定义 Category// 启动 Activity
startActivity(intent)

<intent-filter> 配置

<intent-filter><action android:name="com.example.ACTION_SHOW" /><category android:name="android.intent.category.DEFAULT" /><category android:name="com.example.CATEGORY_PRIVATE" />
</intent-filter>

⭐️putExtra()

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

Service

生命周期
  • onCreate
  • onStartCommand
  • onBind
  • onUnbind
  • onDestroy

37.3-Android中Service的生命周期

非绑定式Service的生命周期
在这里插入图片描述

两种方法停止service:
一种是stopService方法;
一种是stopself方法。
在这里插入图片描述

绑定式Service生命周期
在这里插入图片描述

解绑不一定销毁;
销毁一定解绑。

在这里插入图片描述

启动方式

startService
bindService

两种启动方式的区别
在这里插入图片描述

绑定服务

ServiceConnection
onServiceConnected

在这里插入图片描述
在这里插入图片描述
一句话总结:
Service 绑定是组件与 Service 通信的方式,ServiceConnection监听连接状态,onServiceConnected 在连接成功时提供 Service 实例,让组件可以调用 Service 的方法。

Service的作用
在这里插入图片描述

BroadcastReceiver

在这里插入图片描述

类型

标准广播
有序广播
在这里插入图片描述
在这里插入图片描述

注册方式
  • 动态注册:在代码中注册。
  • 静态注册:在AndroidManifest.xml中注册。

动态注册
在这里插入图片描述
在这里插入图片描述

class MainActivity : AppCompatActivity() {// 声明广播接收器变量(延迟初始化)lateinit var timeChangeReceiver: TimeChangeReceiveroverride fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)// 2. 创建IntentFilter并添加系统时间变化的Actionval intentFilter = IntentFilter()intentFilter.addAction("android.intent.action.TIME_TICK") // 每分钟发送一次的系统广播// 初始化广播接收器实例timeChangeReceiver = TimeChangeReceiver()// 3. 注册广播接收器(动态注册)registerReceiver(timeChangeReceiver, intentFilter)}override fun onDestroy() {super.onDestroy()// 4. 解除广播接收器注册,防止内存泄漏// 必须与registerReceiver成对出现unregisterReceiver(timeChangeReceiver)}// 1. 定义广播接收器类(逻辑上的第一步:先设计接收器)// 内部类可访问外部Activity成员(如this@MainActivity)inner class TimeChangeReceiver : BroadcastReceiver() {override fun onReceive(context: Context, intent: Intent) {// 处理接收到的广播if (intent.action == "android.intent.action.TIME_TICK") {// 每分钟触发一次Toast提示Toast.makeText(context, "Time has changed", Toast.LENGTH_SHORT).show()}}}
}

静态注册
在这里插入图片描述
在这里插入图片描述

// 1. 定义广播接收器类,继承自 BroadcastReceiver
//    该类需配合 AndroidManifest.xml 中的静态注册使用
class BootCompleteReceiver : BroadcastReceiver() {// 2. 重写 onReceive() 方法,系统在接收到匹配的广播时会调用此方法//    context: 上下文对象,用于访问系统服务//    intent: 携带广播信息的意图对象override fun onReceive(context: Context, intent: Intent) {// 3. 显示 Toast 提示(在屏幕上短暂显示消息)//    context: 上下文//    "Boot Complete": 提示文本//    Toast.LENGTH_LONG: 提示持续时间(约3.5秒)Toast.makeText(context, "Boot Complete", Toast.LENGTH_LONG).show()}
}

在这里插入图片描述

<manifest xmlns:android="http://schemas.android.com/apk/res/android"package="com.example.broadcasttest"><!-- 1. 声明接收系统启动完成广播的权限 --><!-- 若无此权限,即使注册了接收器也无法收到广播 --><uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /><applicationandroid:allowBackup="true"android:icon="@mipmap/ic_launcher"android:label="@string/app_name"android:roundIcon="@mipmap/ic_launcher_round"android:supportsRtl="true"android:theme="@style/AppTheme"><!-- 2. 注册系统启动广播接收器 --><!-- android:name: 指定接收器类名(需与代码中的类名匹配) --><!-- android:enabled: 允许系统实例化此接收器 --><!-- android:exported: 允许接收来自应用外部的广播(系统广播属于外部) --><receiverandroid:name=".BootCompleteReceiver"android:enabled="true"android:exported="true"><!-- 3. 过滤器:指定接收器监听的广播类型 --><!-- 此处仅接收系统启动完成的广播 --><intent-filter><action android:name="android.intent.action.BOOT_COMPLETED" /></intent-filter></receiver></application>
</manifest>

在这里插入图片描述

在这里插入图片描述

自定义广播实现

继承BroadcastReceiver

代码实践

广播发送与接收
IntentFilter
在这里插入图片描述

1.创建广播接收器
在这里插入图片描述

// 1. 定义自定义广播接收器,继承自系统广播接收器基类
//    需配合 AndroidManifest.xml 静态注册或代码动态注册使用
class MyBroadcastReceiver : BroadcastReceiver() {// 2. 重写 onReceive() 方法,当接收到匹配的广播时自动调用//    context: 上下文对象,用于获取系统服务或启动组件//    intent: 携带广播数据的意图对象,包含 action 和 extrasoverride fun onReceive(context: Context, intent: Intent) {// 3. 显示短提示消息(实际场景需根据广播类型执行不同逻辑)//    注意:onReceive() 在主线程执行,避免耗时操作(如网络请求)Toast.makeText(context,                    // 上下文"received in MyBroadcastReceiver",  // 提示文本Toast.LENGTH_SHORT          // 显示时长(约2秒)).show()}
}

2.注册广播接收器
静态注册
在这里插入图片描述
3.发送广播
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

一句话总结:
创建广播接收器→
注册(动态 / 静态)→
用 Intent + sendBroadcast 等方法发送→
在接收器 onReceive 处理 。

ContentProvider

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
教师ppt:
在这里插入图片描述

内容URI结构

authority
path
在这里插入图片描述

访问数据的组件

ContentResolver
在这里插入图片描述
在这里插入图片描述

// 获得一个cursor对象
// contentResolver 是 ContentResolver 类型的对象,用于与内容提供者(ContentProvider)交互,实现跨进程数据查询等操作
// query 方法用于向指定内容提供者发起查询请求,参数含义分别是:
// uri:内容提供者中数据的唯一标识,指定要查询哪个内容提供者里的哪些数据,比如联系人、短信等对应不同固定 Uri
// projection:要查询返回的列(字段)列表,类似 SQL 里的 SELECT 后面跟的字段,传 null 表示查询所有列
// selection:查询条件,类似 SQL 里的 WHERE 子句,传 null 表示不做条件限制
// selectionArgs:配合 selection 使用,用于替换 selection 里的占位符(如 ?),避免 SQL 注入,传 null 表示没有占位符参数
// sortOrder:结果排序规则,类似 SQL 里的 ORDER BY 子句,传 null 表示使用默认排序
val cursor = contentResolver.query(uri,projection,selection,selectionArgs,sortOrder
)// 通过cursor来读取数据
// moveToNext 方法会将游标(cursor)移动到结果集的下一行,初始时游标在第一行之前,第一次调用就会移动到第一行;返回值为 true 表示移动成功(有数据行),false 表示已到末尾(没有更多数据行了)
while (cursor.moveToNext()) {// getColumnIndex 方法根据列名("column1")获取该列在结果集中的索引位置,后续通过索引去取对应数据// getString 方法根据列索引,获取当前行对应列的字符串类型数据val column1 = cursor.getString(cursor.getColumnIndex("column1"))// getInt 方法根据列索引,获取当前行对应列的整型数据val column2 = cursor.getInt(cursor.getColumnIndex("column2")) 
}
// 关闭 cursor,释放相关资源,比如数据库连接、内存等,避免出现内存泄漏等问题,使用完 cursor 后务必调用
cursor.close()

在这里插入图片描述

// 1. 创建 ContentValues 对象,用于存储待插入的数据
//    "column1" to "text": 键值对表示列名和对应的值(字符串类型)
//    "column2" to 1: 键值对表示列名和对应的值(整型)
val values = contentValuesOf("column1" to "text", "column2" to 1) // 2. 向 ContentProvider 发起插入请求
//    uri: 指定插入数据的目标 URI(如 content://com.example.provider/table)
//    values: 包含待插入数据的 ContentValues 对象
//    返回值: 插入新记录的 URI(通常包含新记录的 ID)
contentResolver.insert(uri, values)

在这里插入图片描述

// 1. 创建 ContentValues 对象,存储要更新的数据
//    "column1" to "": 将 column1 的值更新为空字符串
val values = contentValuesOf("column1" to "")// 2. 向 ContentProvider 发起更新请求
//    uri: 指定更新数据的目标 URI(如 content://com.example.provider/table)
//    values: 包含要更新数据的 ContentValues 对象
//    "column1 = ? and column2 = ?": WHERE 子句,使用占位符 ? 防止 SQL 注入
//    arrayOf("text", "1"): 占位符对应的实际参数值,按顺序替换 ?
//    返回值: 受影响的行数(更新成功的记录数量)
contentResolver.update(uri, values, "column1 = ? and column2 = ?", 
arrayOf("text", "1"))

在这里插入图片描述

// 1. 向 ContentProvider 发起删除请求
//    uri: 指定删除数据的目标 URI(如 content://com.example.provider/table)
//    "column2 = ?": WHERE 子句,使用占位符 ? 防止 SQL 注入
//    arrayOf("1"): 占位符对应的实际参数值,替换 ?
//    返回值: 受影响的行数(删除成功的记录数量)
contentResolver.delete(uri, "column2 = ?", arrayOf("1"))
MIME类型格式getType()

vnd.android.cursor.dir
vnd.android.cursor.item

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

vnd.android.cursor.dir
vnd.android.cursor.item
在这里插入图片描述
在这里插入图片描述

vnd.android.cursor.dir/ :表示返回一组数据
vnd.android.cursor.item/ :表示返回单条数据

通配符

*(任意长度字符)
#(任意长度数字)
在这里插入图片描述

第三章 通知与后台任务

在这里插入图片描述

通知机制

在这里插入图片描述

创建通知渠道

NotificationChannel

通知渠道
在这里插入图片描述

创建通知渠道
在这里插入图片描述
(内容同上)

//1、创建一个NotificationChannel对象,为通知渠道设置名称、描述和重要性级别。
NotificationChannel channel = new NotificationChannel(CHANNEL_ID, name, importance);
//2、创建一个NotificationManager。
NotificationManager notificationManager = getSystemService(NotificationManager.class);
//3、使用NotificationManager.createNotificationChannel()方法将通知渠道添加到系统
中。
notificationManager.createNotificationChannel(channel);
//1、创建一个NotificationChannel对象,为通知渠道设置名称、描述和重要性级别。
val channel = NotificationChannel(Channel_ID, name, importance)
//2、创建一个NotificationManager。
val manager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
//3、使用NotificationManager.createNotificationChannel()方法将通知渠道添加到系统
中。
manager.createNotificationChannel(channel)

在这里插入图片描述

通知构建

NotificationCompat.Builder

在这里插入图片描述

// 1. 获取系统通知服务,用于发送和管理通知
//    Context.NOTIFICATION_SERVICE: 通知服务的系统标识符
//    NotificationManager: 负责通知的创建、发送和取消等操作
val manager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager// 2. 使用 NotificationCompat.Builder 创建通知(兼容低版本 Android)
//    context: 上下文对象,用于获取资源和系统服务
//    channelId: 通知渠道 ID(Android 8.0+ 必须指定,用于分类通知)
val notification = NotificationCompat.Builder(context, channelId).setContentTitle("This is content title")     // 设置通知标题(显示在顶部).setContentText("This is content text")       // 设置通知内容(显示在标题下方).setSmallIcon(R.drawable.small_icon)          // 设置状态栏和通知栏的小图标(必填).setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.large_icon)) // 设置通知左侧的大图标(可选).build()                                      // 构建通知对象// 3. 发送通知
//    1: 通知的唯一标识符(用于更新或取消通知)
//    notification: 要发送的通知对象
manager.notify(1, notification)

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
场景类比:快递包裹(PendingIntent)
假设你要寄一个快递(PendingIntent),四个参数就像这样:
context = 寄件人地址
快递从哪里发出(应用环境),快递公司(系统)需要知道从哪取件。
requestCode = 包裹编号
同一个地址(context)可能寄多个包裹,用编号区分不同包裹(如:001、002)。
即使包裹内容(intent)相同,编号不同就是不同的包裹。
intent = 包裹内容
里面装的是什么(如手机、衣服),对应要执行的操作(如启动 Activity、发送广播)。
flags = 快递特殊要求
例如:
FLAG_IMMUTABLE = 包裹封条不可拆(安全性)。
FLAG_UPDATE_CURRENT = 如果已有相同编号的包裹,用新包裹替换旧的。
FLAG_ONE_SHOT = 包裹只能签收一次,签收后失效。

// 创建点击通知后要启动的 Activity 的意图
val intent = Intent(this, NotificationActivity::class.java)// 将 Intent 包装为 PendingIntent,允许系统在用户点击通知时执行该意图
// 注意:最后一个参数 0 表示默认标志位,建议改用 FLAG_IMMUTABLE 提高安全性
val pi = PendingIntent.getActivity(this, 0, intent, 0)// 获取系统通知服务
val manager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager// 构建通知内容
val notification = NotificationCompat.Builder(context, channelId).setContentTitle("This is content title").setContentText("This is content text").setSmallIcon(R.drawable.small_icon).setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.large_icon)).setContentIntent(pi) // 设置点击通知后执行的 PendingIntent.build()// 发送通知(ID=1 用于标识该通知,可用于后续更新或取消)
manager.notify(1, notification)

在这里插入图片描述

使用了 FLAG_IMMUTABLE(安全推荐)

多媒体处理

音频播放

MediaPlayer类
prepare
start
stop
在这里插入图片描述
在这里插入图片描述

一个简单的音乐播放器示例代码

class MainActivity : AppCompatActivity() {// 1. 创建一个MediaPlayer对象(类成员变量,保证全局可访问)private val mediaPlayer = MediaPlayer()override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)// 初始化MediaPlayer(包含设置数据源和准备操作)initMediaPlayer()// 2. 调用setDataSource()设置音频文件路径 + 3. 调用prepare()进入准备状态private fun initMediaPlayer() {// 获取资源管理器(用于访问assets目录文件)val assetManager = assets// 从assets目录打开音频文件(路径为"music.mp3")val fd = assetManager.openFd("music.mp3")// 2. 设置数据源(指定文件描述符、起始偏移量、文件长度)mediaPlayer.setDataSource(fd.fileDescriptor, fd.startOffset, fd.length) // 3. 同步调用prepare()进入准备状态(会阻塞线程,建议在子线程调用)mediaPlayer.prepare()}// 播放按钮点击事件play.setOnClickListener {if (!mediaPlayer.isPlaying) {// 4. 调用start()方法开始播放mediaPlayer.start() }}// 暂停按钮点击事件pause.setOnClickListener {if (mediaPlayer.isPlaying) {// 4. 调用pause()方法暂停播放mediaPlayer.pause() }}// 停止按钮点击事件stop.setOnClickListener {if (mediaPlayer.isPlaying) {// 4. 调用reset()方法停止播放(重置状态)mediaPlayer.reset() // 重新初始化播放器(相当于重新设置数据源和准备)initMediaPlayer()}}}override fun onDestroy() {super.onDestroy()// 5. 释放MediaPlayer对象资源(必须在Activity销毁时调用)// 先停止播放(虽然reset()已停止,但显式调用更安全)mediaPlayer.stop() // 释放底层音频资源,防止内存泄漏mediaPlayer.release() }
}
视频播放

VideoView组件
支持res/raw目录资源

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

class MainActivity : AppCompatActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)// 1. 创建视频文件的URI(通过android.resource方案访问raw目录资源)//    android.resource://包名/资源ID → 固定格式val uri = Uri.parse("android.resource://$packageName/${R.raw.video}")// 2. 设置视频数据源(URI指向raw目录下的video.mp4文件)videoView.setVideoURI(uri)play.setOnClickListener {if (!videoView.isPlaying) {videoView.start() // 3. 若视频未播放,调用start()开始播放}}pause.setOnClickListener {if (videoView.isPlaying) {videoView.pause() // 3. 若视频正在播放,调用pause()暂停播放}}replay.setOnClickListener {if (videoView.isPlaying) {videoView.resume() // 4. 如果视频正在播放,调用resume()从暂停状态恢复播放(重新播放)}}override fun onDestroy() {super.onDestroy()videoView.suspend() // 5. Activity销毁时调用suspend()暂停播放并释放资源(非释放性销毁,可恢复)}}
}

第四章 数据存储与通信

在这里插入图片描述

SharedPreferences

数据存取流程

edit
putXxxxx
commit
在这里插入图片描述
在这里插入图片描述

存储到SharedPreferences:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

// 1. 获取 SharedPreferences 实例(用于存储键值对数据)
//    "data": 文件名(存储在 /data/data/包名/shared_prefs/data.xml)
//    MODE_PRIVATE: 文件私有模式(其他应用无法访问)
val editor = getSharedPreferences("data", Context.MODE_PRIVATE).edit()// 2. 向编辑器中添加键值对数据(支持多种数据类型)
editor.putString("name", "Tom")    // 存储字符串类型数据
editor.putInt("age", 28)          // 存储整数类型数据
editor.putBoolean("married", false) // 存储布尔类型数据// 3. 提交修改(异步方式)
//    apply(): 异步写入磁盘,无返回值(推荐,不阻塞UI线程)
//    commit(): 同步写入磁盘,返回布尔值表示成功/失败
editor.apply()

从SharedPreferences中读取:
在这里插入图片描述
在这里插入图片描述

// 1. 获取一个SharedPreferences对象
//    "data": 文件名(对应之前写入的XML文件)
//    MODE_PRIVATE: 确保只能访问当前应用的SharedPreferences
val prefs = getSharedPreferences("data", Context.MODE_PRIVATE)// 2. 读取数据:从SharedPreferences中获取对应类型的值
//    getString("name", ""): 获取名为"name"的字符串,默认值为空字符串
//    getInt("age", 0): 获取名为"age"的整数,默认值为0
//    getBoolean("married", false): 获取名为"married"的布尔值,默认值为false
val name = prefs.getString("name", "")
val age = prefs.getInt("age", 0)
val married = prefs.getBoolean("married", false)
文件存储

在这里插入图片描述

写入文件的步骤:
在这里插入图片描述
在这里插入图片描述

fun save(inputText: String) {try {// 1. 获取应用程序的上下文Context对象(通过openFileOutput()隐式调用)//    注意:在Activity中可直接调用openFileOutput(),因Activity继承自Context// 2. 调用Context对象的openFileOutput()方法创建一个FileOutputStream对象//    "data": 文件名(存储在应用内部目录)//    MODE_PRIVATE: 文件私有模式(其他应用无法访问)val output = openFileOutput("data", Context.MODE_PRIVATE)// 3. 通过FileOutputStream对象将数据写入文件中(需借助流桥接器和缓冲器)//    OutputStreamWriter: 字节流 → 字符流的桥接器(指定UTF-8编码)//    BufferedWriter: 为字符流添加缓冲区,提高写入效率val writer = BufferedWriter(OutputStreamWriter(output))// 使用use函数自动管理流的生命周期(自动调用close())writer.use {// 写入文本内容到缓冲区(最终通过桥接器转为字节写入文件)it.write(inputText)}// 4. 关闭FileOutputStream、OutputStreamWriter、BufferedWriter对象//    注意:writer.use{}已自动关闭writer和底层的outputStream//    此行output.close()冗余,可删除(重复关闭可能导致异常)output.close()} catch (e: IOException) {// 异常处理:打印IO错误堆栈信息e.printStackTrace()}
}

读取文件的步骤:
在这里插入图片描述
在这里插入图片描述

fun load(): String {val content = StringBuilder()try {// 1. 获取应用程序的上下文Context对象(通过openFileInput()隐式调用)//    注意:在Activity中可直接调用openFileInput(),因Activity继承自Context// 2. 调用Context对象的openFileInput()方法创建一个FileInputStream对象//    "data": 要读取的文件名(位于应用内部存储目录)val input = openFileInput("data")// 3. 通过InputStreamReader()创建一个InputStreamReader对象//    InputStreamReader: 字节流 → 字符流的桥接器(默认使用UTF-8编码)val reader = BufferedReader(InputStreamReader(input))// 4. 通过BufferedReader()传入上述InputStreamReader对象,创建带缓冲的字符读取器//    BufferedReader: 为字符流添加缓冲区,提高读取效率// 5. 用BufferedReader的forEachLine()或readLine()读取每一行的数据//    forEachLine: Kotlin扩展函数,遍历每一行并执行lambda表达式//    content.append(it): 将每行内容追加到StringBuilderreader.use {reader.forEachLine {content.append(it)}}// 6. 关闭FileInputStream、InputStreamReader、BufferedReader对象//    注意:reader.use{}已自动关闭reader和底层的inputStream//    无需手动调用close()} catch (e: IOException) {// 异常处理:打印IO错误堆栈信息e.printStackTrace()}return content.toString()
}

SQLite

在这里插入图片描述

SQLiteOpenHelper

onCreate
onUpgrade
在这里插入图片描述
在这里插入图片描述

创建数据库:
在这里插入图片描述
在这里插入图片描述

// 1. 创建一个类并继承SQLiteOpenHelper
//    MyDatabaseHelper: 自定义数据库帮助类,负责管理数据库创建和版本更新
class MyDatabaseHelper(val context: Context, name: String, version: Int) : SQLiteOpenHelper(context, name, null, version) {// 定义创建表的SQL语句(Book表:包含ID、作者、价格、页数、书名字段)private val createBook = "create table Book (" +"id integer primary key autoincrement," +"author text," +"price real," +"pages integer," +"name text)"// 3. 在onCreate()方法中,编写SQL语句来创建表//    首次创建数据库时调用(数据库文件不存在时触发)override fun onCreate(db: SQLiteDatabase) {db.execSQL(createBook)  // 执行SQL创建表Toast.makeText(context, "Create succeeded", Toast.LENGTH_SHORT).show()}// 4. 在onUpgrade()方法中,编写SQL语句来升级表//    数据库版本号增加时调用(需手动修改构造函数中的version参数)override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {// 当前为空实现(实际开发中需添加表结构更新逻辑,如:// db.execSQL("DROP TABLE IF EXISTS Book");// onCreate(db);}
}

升级数据库
~
在这里插入图片描述
在这里插入图片描述

override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {// 1. 先删除旧表(简单粗暴的升级方式,会丢失所有数据)//    注意:实际生产环境中不建议直接删除表,应采用数据迁移策略db.execSQL("drop table if exists Book")db.execSQL("drop table if exists Category")// 2. 重新创建表结构(调用onCreate方法)//    由于旧表已删除,新表将是空的(数据丢失)onCreate(db)
}

升级数据库的最佳写法
在这里插入图片描述

第一版:

// 第一版:仅创建 Book 表
private val createBook = "create table Book (" +"id integer primary key autoincrement," +"author text," +"price real," +"pages integer," +"name text)"override fun onCreate(db: SQLiteDatabase?) {db?.execSQL(createBook) // 首次创建数据库时只创建 Book 表Toast.makeText(context, "Create succeeded", Toast.LENGTH_SHORT).show()
}override fun onUpgrade(db: SQLiteDatabase?, oldVersion: Int, newVersion: Int) {// 第一版无需升级逻辑(初始版本)
}

第二版:

// 定义创建 Book 表的 SQL 语句,包含 id(主键自增)、author、price、pages、name 字段
private val createBook = "create table Book (" +"id integer primary key autoincrement," +"author text," +"price real," +"pages integer," +"name text)"// 定义创建 Category 表的 SQL 语句,包含 id(主键自增)、category_name、category_code 字段
private val createCategory = "create table Category (" +"id integer primary key autoincrement," +"category_name text," +"category_code integer)"// 重写 onCreate 方法,数据库首次创建时调用,用于初始化表结构
override fun onCreate(db: SQLiteDatabase?) {// 执行创建 Book 表的 SQL 语句,db 为可空类型,使用 ?. 安全调用db?.execSQL(createBook)// 执行创建 Category 表的 SQL 语句db?.execSQL(createCategory)// 弹出 Toast 提示,告知用户表创建成功Toast.makeText(context, "Create succeeded", Toast.LENGTH_SHORT).show()
}// 重写 onUpgrade 方法,数据库版本升级时调用,用于更新表结构
override fun onUpgrade(db: SQLiteDatabase?, oldVersion: Int, newVersion: Int) {// 判断旧版本号是否小于等于 1,若是则执行创建 Category 表的操作// 说明从版本 1 升级到更高版本(这里是第 2 版)时,需要补充创建 Category 表if (oldVersion <= 1) {db?.execSQL(createCategory)}// 此处第 2 版代码中这部分可能是未完整显示,从逻辑看是为后续版本升级预留或示例// 比如后续第 3 版要给 Book 表加字段时,会补充对应的判断逻辑
}

第三版:

// 定义创建 Book 表的 SQL 语句,在原有基础上新增 category_id 字段
private val createBook = "create table Book (" +"id integer primary key autoincrement," +"author text," +"price real," +"pages integer," +"name text," +"category_id integer)"// 定义创建 Category 表的 SQL 语句,和第 2 版一致,包含 id、category_name、category_code 字段
private val createCategory = "create table Category (" +"id integer primary key autoincrement," +"category_name text," +"category_code integer)"// 重写 onCreate 方法,数据库首次创建时调用,用最新的表结构初始化
override fun onCreate(db: SQLiteDatabase?) {// 执行创建带 category_id 字段的 Book 表的 SQL 语句db?.execSQL(createBook)// 执行创建 Category 表的 SQL 语句db?.execSQL(createCategory)// 弹出 Toast 提示表创建成功Toast.makeText(context, "Create succeeded", Toast.LENGTH_SHORT).show()
}// 重写 onUpgrade 方法,处理数据库版本升级时的表结构变更
override fun onUpgrade(db: SQLiteDatabase?, oldVersion: Int, newVersion: Int) {// 若旧版本号 <= 1,执行创建 Category 表操作,适配从第 1 版升级的情况if (oldVersion <= 1) {db?.execSQL(createCategory)}// 若旧版本号 <= 2,执行给 Book 表添加 category_id 字段的操作// 说明从版本 2 升级到第 3 版时,需要补充添加该字段,保证表结构更新if (oldVersion <= 2) {db?.execSQL("alter table Book add column category_id integer")}
}
版本数据库结构变更onCreate() 逻辑onUpgrade() 逻辑
第一版仅创建 Book 表执行 createBook空(无需升级)
第二版新增 Category 表同时执行 createBook 和 createCategory若 oldVersion <= 1,则创建 Category 表
第三版Book 表新增 category_id 字段创建带 category_id 的 Book 表1. 若 oldVersion <= 1,创建 Category 表
2. 若 oldVersion <= 2,添加 category_id 字段
SQLiteDatabase

update
delete
insert
query
rawQuery
execSQL
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

rawQuery
在这里插入图片描述

在这里插入图片描述

execSQL
在这里插入图片描述

数据库操作

getWritableDatabase
在这里插入图片描述

在这里插入图片描述
一句话总结getReadableDatabase() 和 getWritableDatabase() 的核心区别:
getReadableDatabase():能读则读,不能读也不崩溃(降级处理)。
getWritableDatabase():必须能写,否则报错(强一致性)。

网络与数据格式

JSON与XML对比


结构
可读性
带宽

对比维度JSONXML
结构基于键值对({key:value})和数组,语法紧凑,贴近编程语言数据结构(如对象、列表)基于标签 <tag></tag> 嵌套,需显式定义标签,结构高度文档化(类似 HTML 标签逻辑)
可读性对开发者友好(熟悉代码语法即可理解),但复杂嵌套时纯数据块可能难直观关联业务语义标签语义化强(标签名可自定义说明),人工阅读时结构清晰;但冗余标签会增加视觉和理解负担
带宽无冗余标签,数据体积小,传输效率高(适合网络请求、API 交互)标签重复(每个数据项需开闭标签),文件体积大,传输占带宽更高(大数据量场景劣势明显)
JSON解析库

在这里插入图片描述
GSON
JSONObject

GSON
在这里插入图片描述

在这里插入图片描述

JSONObject
在这里插入图片描述

第五章 UI开发

常用组件/控件

显示类

TextView
ProgressBar
WebView

TextView
在这里插入图片描述
⭐️属性 layout_width & layout_height

  • 指定控件的宽度和高度
  • 这两个必须配置!
  • 3种可选值:
    • match_parent:“让这个视图的大小和其父视图一样大”
    • wrap_content:“让这个视图的大小足够大以适应其内容”
    • 固定值:建议使用 dp(density-independent pixel)或 sp(scale-independent pixel)

⭐️属性 android:gravity

  • 指定控件内容(文字、图片……)的对齐方式
  • 可选值有top、bottom、start、end、center,可以用“|”来指定多个值

ProgressBar
在这里插入图片描述
⭐️属性 android:visibility

  • 所有控件都具有的属性
  • 可选值:visible、invisible和gone
  • 可在代码中设置控件的可见性:setVisibility(),可传入的值有View.VISIBLE、View.INVISIBLE和View.GONE

在这里插入图片描述

⭐️水平进度条

  • style=“?android:attr/progressBarStyleHorizontal”
  • android:max=“100”

WebView
(ppt第11章)
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

输入类

EditText
在这里插入图片描述
在这里插入图片描述

多媒体类

VideoView
ImageView

VideoView
VideoView

ImageView
在这里插入图片描述
在这里插入图片描述

布局容器
Fragment

在这里插入图片描述

Fragment状态
  • 生命周期
    • 运行
    • 暂停
    • 停止
    • 销毁

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

动态加载Fragment

事务管理

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

// 主Activity类,继承自AppCompatActivity
class MainActivity : AppCompatActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main) // 设置布局文件// 步骤1:初始化按钮并设置点击事件val button: Button = findViewById(R.id.button)button.setOnClickListener {// 步骤1.1:创建待添加Fragment的实例(点击时替换为AnotherRightFragment)replaceFragment(AnotherRightFragment())}// 步骤1.2:Activity加载时默认添加RightFragmentreplaceFragment(RightFragment())}// 动态添加/替换Fragment的方法private fun replaceFragment(fragment: Fragment) {// 步骤2:获取FragmentManager(管理Activity中的Fragment)val fragmentManager = supportFragmentManager// 步骤3:开启事务(所有Fragment操作必须在事务中执行)val transaction = fragmentManager.beginTransaction()// 步骤4:替换Fragment// 参数1:容器ID(R.id.rightLayout对应布局中的FrameLayout)// 参数2:待添加的Fragment实例transaction.replace(R.id.rightLayout, fragment)// 步骤5:提交事务(使变更生效)transaction.commit()}
}
平板大尺寸

在这里插入图片描述

LinearLayout(水平/垂直)

在这里插入图片描述

垂直
在这里插入图片描述

水平
在这里插入图片描述

LinearLayout使用layout_gravity属性对齐的效果
在这里插入图片描述

LinearLayout使用layout_weight属性计算屏占比
在这里插入图片描述

属性与操作

文本属性

android:text
在这里插入图片描述
在这里插入图片描述

图片资源引用

android:src
在这里插入图片描述

动态替换Fragment

replace
事务提交
动态加载Fragment

在这里插入图片描述

布局管理

适配不同屏幕

限定符如large
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

LinearLayout特性

水平/垂直排列
LinearLayout(水平/垂直)


题目

【Android开发】移动程序设计期末复习练习题(二)

Android复习题

选择题

单选题:15题、30分
多选题:10题、20分 全对满分,少选得半分,选错不得分在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

onCreate 创造
onStart 开始
onResume 恢复
onPause 暂停
onStop 停止
onDestroy 销毁
onRestart 重新开始 stop->
记忆:都是on开头的

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

另一种:startService()在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

简答题(4题、20分)

Android基础入门

3.简述Android系统架构包含的层次以及各层的特点。

答:
Android系统架构从高到低分为四层,分别是应用程序层、应用程序框架层、核心类库、Linux内核

应用程序层:一个核心应用程序的集合,安装在手机中的应用程序都属于这一层。

应用程序框架层:主要提供了构建应用程序时用到的各种API。

核心类库:包含了系统库和Android运行环境

Linux内核:为Android设备的各种硬件提供了底层的驱动。

Android常见页面布局

列举Android中的常用布局,并简述他们各自的特点。
答:
RelativeLayout(相对布局):通过相对位置的方式来指定布局内子控件的位置。
LinerLayout(线性布局):通过android:orientation属性来指定子控件水平垂直排列。
TableLayout(表格布局):采用行列的方式来管控布局,一个TableRow代表一行。
FrameLayout(帧布局):该布局会在屏幕上创建一块空白的区域,添加到该区域的每一个子控件占一帧,这些帧会一个一个叠加在一起,后加入的控件会叠加在上一个控件上层。默认情况下,帧布局中所有控件会与左上角对齐。

Android常见界面控件

简述实现Button按钮的点击事件的方式有哪几种?
答:
1、在布局文件中指定onClick属性的方式设置点击事件。

2、使用匿名内部类的方式设置点击事件。

3、通过为Activity实现OnClickListener接口的方式设置点击事件。

程序活动单元Activity

简述Activity的生命周期的方法及什么时候被调用。
答:
onCreate():Activity创建时调用,通常做一些初始化配置
onStart():Activity即将可见时调用。
onResume():Activity获取焦点时调用
onPause():当前Activity被其他Activity覆盖或锁屏时调用
onDestroy():Activity销毁时调用。
onRestart():Activity从停止状态到再次启动时调用。

简述Activity的四种启动模式及其特点。
答:
1.standard:每次启动均创建新实例;
2.singleTop:若目标 Activity 已在栈顶,则复用实例,否则创建新实例。
3.singleTask:若任务栈中存在实例,复用并清空其上方所有 Activity,否则创建新实例。
4.singleInstance:启动activity时,会启动一个新的任务栈管理该activity实例,全局唯一实例。

简述Activity、Intent、IntentFilter的作用
答:
Activity:界面组件,处理用户交互,通过任务栈管理实例。
Intent:组件间通信工具,分显式和隐式,用于传递数据。
IntentFilter:隐式 Intent 的匹配规则,在Manifest中声明,通过 Action、Data 等过滤可触发的组件。

广播机制

简述广播机制的实现过程。
答:
1.创建广播接收器:写一个类继承 BroadcastReceiver,实现 onReceive() 方法,处理广播逻辑。
2.注册广播接收器:分动态注册和静态注册。
3.发送广播:用 Intent 类发送,标准广播通过 sendBroadcast() ,有序广播通过sendOrderedBroadcast() 。
4.接受广播:在onReceive() 处理接收到的广播。

建 注 发 收

简述有序广播和无序广播的区别。
答:
无序广播:接收器 几乎同时”收到,无先后;无法被截断;无序广播用 sendBroadcast() 发送;
有序广播:按优先级,执行完才传下一个;可以被截断;有序广播用 sendOrderedBroadcast() 发送。

服务

简述Service的两种启动方式的区别。
答:
startService:用于启动服务,一次启动,无限次运行;操作停止时,服务停止。
bindService:用于绑定服务,组件绑定到它时运行;多个组件可绑定,多个组件解绑时销毁服务。

简述Service的生命周期。
答:
非绑定式Service:onCreate(),onStartCommand(),onDestroy;
绑定式Service:onCreate(),onBInd(),onUnbind(),onDestroy;

简述Android数据存储的方式

答:
SharedPreferences:轻量级键值对存储,用于简单配置。
文件存储:分内部和外部,存大量数据。
SQLite 数据库:结构化存储,适合复杂数据。

使用内容提供者共享数据

简述内容提供者的工作原理。
答:
当B程序需要操作A程序数据库中的数据,一般需要A程序使用ContentProvider暴露数据,才能被其他程序操作。B程序通过ContentResolver操作A程序暴露出来的数据,而A程序会将操作结果返回给ContentResolver,然后ContentResolver再将操作结果返回给B程序。

简述内容观察者的工作原理。
答:
使用ContentObserver观察A程序的数据时,首先要在A程序的ContentProvider中调用ContentResolver的notifyChange()方法。调用此方法后,当B程序操作A程序中的数据时,A程序会向“消息中心”发送数据变化的消息,此时C程序会观察到“消息中心”的数据有变化,会触发ContentObserver的onChange()方法。

共用选项题(2大题,2分/小题,共20分)

也就是说每道题5个空

1、在MainActivity组件对应的布局文件里,定义了两个Button按钮,其id分别设置为button1和button2,单击按钮后,分别启动对应的SecondActivity组件和ThirdActivity组件。从MainActivity跳转到ThirdActivity时,往ThirdActivity传递一个Bundle类型的数据。当从ThirdActivity返回到MainActivity时,同时返回给MainActivity一个字符串数据。

(1)调用其他Activity的主调组件MainActivity的代码如下:

public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);//获取id为button1的按钮控件Button button1 =_____(1-1findViewById_______(R.id.button1);button1.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Intent intent = new Intent();//隐式调用SecondActivityintent.setAction("_________(1-2)android.intent.action.ysdy_________"); //启动SecondActivity,第2个参数为请求码_______(1-3startActivityForResult____________(intent, 2); }} );//获取id为button2的按钮控件Button button2=findViewById(_____(1-4R.id.button2_________);button2.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Intent intent = new Intent();//显示调用ThirdActivityintent.setClass(MainActivity.this, _____(1-5ThirdActivity.class_________); //设置Bundle类型数据Bundle bundle = new Bundle(); bundle.putString("name", "张三");bundle.___ (1-6putInt____("age", 20);//通过意图对象携带数据intent.putExtra("data", bundle); //启动ThirdActivity并请求数据回传,第2个参数为请求码startActivityForResult(intent, 3); }} );}@Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent data) {super.onActivityResult( requestCode, resultCode, data);//判断是哪个Activity返回的数据,使用结果码if(resultCode==3) {//获取返回的数据String string = data.getStringExtra("hello");}}}

(2)其中,在清单文件里,对被调用的第2个Activity组件配置如下:

<activityandroid:name=".SecondActivity"android:label="隐式调用SecondActivity"><intent-filter><action android:name="android.intent.action.ysdy" /><category android:name="android.intent.category.DEFAULT" /></intent-filter></activity>

(3)第2个Activity组件的代码如下:

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

(4)第3个Activity组件接收从MainActivity传递的捆绑数据,返回前设置非捆绑数据和结果码,其代码如下:

public class ThirdActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_third);String receiver="接收的数据如下: \n";Intent intent=getIntent();Bundle data= intent.getBundleExtra("data");  //获取捆绑数据receiver+="name: "+data.getString("name")+"\n";receiver+="age: "+data.getInt("age");//在屏幕上显示接收到的数据Toast.makeText(this, receiver, Toast.LENGTH_LONG).show();//通过意图对象携带返回数据intent=new Intent();intent.___ (1-7putExtra______("hello","How are you?"); //设置返回数据和结果码_____(1-8startActivityForResult_______(3,intent); }}

2、编写一个程序,根据不同的Uri获取联系人表中的相关信息如下所示:

(1)通过ContactsContract.Contacts.CONTENT_URI的Uri获取Contacts表中的联系人id和姓名,其字段分别为ContactsContract.Contacts._ID、ContactsContract.Contacts.DISPLAY_NAME。

(2)通过ContactsContract.CommonDataKinds.Phone.CONTENT_URI的Uri获取Data表中的联系人id和电话,其字段分别为ContactsContract.CommonDataKinds.Phone.CONTACT_ID、ContactsContract.CommonDataKinds.Phone.NUMBER。

请根据上述系统联系人数据库的相关信息,编写一个程序,用于读取系统联系人的姓名和电话,并将读取的信息显示在界面中。

public class MainActivity extends AppCompatActivity implements View.OnClickListener {private TextView textView;private Button query_contacts;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);query_contacts = findViewById(R.id.query_contacts);query_contacts.setOnClickListener(this);textView = findViewById(R.id.tv);}@Overridepublic void onClick(View v) {//动态申请读取手机通讯录权限ActivityCompat.___ (2-1requestPermissions______(MainActivity.this, new String[]{"android.permission.READ_CONTACTS"}, 1);}@Overridepublic void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {super.onRequestPermissionsResult(requestCode, permissions, grantResults);if (requestCode == 1) {for (int i = 0; i < permissions.length; i++) {if (permissions[i].equals("android.permission.READ_CONTACTS")&& grantResults[i] == PackageManager.___ (2-2PERMISSION_GRANTED______) {Toast.makeText(MainActivity.this,"已获取权限", Toast.LENGTH_SHORT).show();fetchContactInformation();}else{finish();}}}}//读取手机联系人信息的方法public void fetchContactInformation() {String id,name,phoneNumber;//定义一个字符串变量,用于保存查询结果String contacts = "";//获取内容解析器对象,用于对内容提供者的数据进行操作ContentResolver contentResolver = this.___ (2-3getContentResolver()______;//首先查询手机联系人表获取联系人的id和姓名Cursor cursor = contentResolver.query(ContactsContract.Contacts.CONTENT_URI,null, null, null, null);while(cursor.moveToNext()) {//获取联系人idid = cursor.getString(cursor.getColumnIndex(___ (2-4ContactsContract.Contacts._ID______));//获取联系人姓名name = cursor.getString(cursor.getColumnIndex(___ (2-5ContactsContract.Contacts.DISPLAY_NAME______));contacts+= "姓名:"+name+"\n";//然后查询手机联系人数据表获取联系人的电话号码//根据id查询相应联系人的电话Cursor phoneCursor = contentResolver.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,null, ___ (2-6ContactsContract.CommonDataKinds.Phone.CONTACT_ID______ + "=" + id, null, null);contacts+= "电话:";while(phoneCursor.moveToNext()) {phoneNumber = phoneCursor.getString(phoneCursor.getColumnIndex(___ (2-7ContactsContract.CommonDataKinds.Phone.NUMBER______));contacts+= phoneNumber +"         ";}contacts+="\n\n";phoneCursor.close();}//在界面上显示所查询到的所有手机联系人信息textView.setText(contacts);cursor.close();}}

综合题(10分)

使用TableLayout布局实现一个简单的计算器界面。

开发一个整数加法的程序,实现将计算结果显示到界面上的功能。

开发一个自定义对话框,其界面中显示标题、提示内容、确定和取消按钮。当点击回退健时,用于提示用户是否退出应用。


2025.6.5考试

第三大题 共用选项题
1.Service
2.动态添加Fragment

第四大题 简答题
1.引用图片资源方式
2.使用音频资源方式
3.Activity的生命周期
4.动态添加Fragment

背了那么多,尽考些有的没的

😄~~end~~😄

http://www.xdnf.cn/news/887059.html

相关文章:

  • 能不能用string接收数据库的datetime类型字段
  • ServBay 1.13.0 更新,新增第三方反向代理/内网穿透
  • 【C语言练习】082. 使用C语言实现简单的加密算法
  • 钉钉 - 机器人消息推送(签名版)
  • 【C++高阶二】STL的map和set
  • 软件测试基础知识总结
  • 基于51单片机的温控电机系统
  • Axure 与 Cursor 集成实现方案
  • 服务虚拟化HoverFly
  • MySQL中的部分问题(1)
  • EXCEL如何快速批量给两字姓名中间加空格
  • 区间动态规划
  • Next.js中Protected Route(受保护路由)
  • Next.js 中间件鉴权绕过漏洞 CVE-2025-29927
  • [Java恶补day16] 238.除自身以外数组的乘积
  • 命名管道实现本地通信
  • 回溯算法复习(1)
  • Flash烧录速度和加载配置速度(纯FPGA ZYNQ)
  • 基于RK3568的多网多串电力能源1U机箱解决方案,支持B码,4G等
  • Selenium常用函数介绍
  • 深度解码:我如何用“结构进化型交互学习方法”与AI共舞,从学习小白到构建复杂认知体系
  • 【Web】D^3CTF 2025题解
  • 打卡Day45
  • Redis(02)Win系统如何将Redis配置为开机自启的服务
  • 如何选择专业数据可视化开发工具?为您拆解捷码全功能和落地指南!
  • Android 进程分类
  • 5G 网络中 DRX(非连续接收)技术深度解析
  • java: 找不到符号 符号: 变量 log
  • 【opencv】基础知识到进阶(更新中)
  • Modern C++(三)表达式