337 lines
11 KiB
Markdown
337 lines
11 KiB
Markdown
|
|
---
|
|||
|
|
tags: [嵌入式系统, 复习, Android开发]
|
|||
|
|
create time: 2026-06-10 11:11
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# Android应用开发基础
|
|||
|
|
|
|||
|
|
## 概述
|
|||
|
|
本文档覆盖Android应用开发的核心知识,包括分层架构、四大组件、Activity生命周期、数据存储、UI布局、权限管理和常用设计模式。这是嵌入式系统课程中移动终端开发部分的复习重点。
|
|||
|
|
|
|||
|
|
## 正文
|
|||
|
|
|
|||
|
|
### 1. Android分层架构
|
|||
|
|
|
|||
|
|
Android系统采用分层架构设计,从底层到顶层分为四层:
|
|||
|
|
|
|||
|
|
```mermaid
|
|||
|
|
graph TD
|
|||
|
|
A["Applications"] --> B["Application Framework"]
|
|||
|
|
B --> C["Libraries / Android Runtime"]
|
|||
|
|
C --> D["Linux Kernel"]
|
|||
|
|
|
|||
|
|
style A fill:#4fc3f7
|
|||
|
|
style B fill:#81d4fa
|
|||
|
|
style C fill:#b3e5fc
|
|||
|
|
style D fill:#ffcc80
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
| 层级 | 组成 | 说明 |
|
|||
|
|
|------|------|------|
|
|||
|
|
| **Applications** | 短信、电话、浏览器、第三方App | 用户直接使用的应用 |
|
|||
|
|
| **Application Framework** | Activity Manager, Content Provider, Resource Manager, Notification Manager | 提供构建应用的基础API |
|
|||
|
|
| **Libraries / Runtime** | SQLite, OpenGL, WebKit, Media Framework, Dalvik/ART | 系统库和运行时环境 |
|
|||
|
|
| **Linux Kernel** | 驱动、内存管理、进程管理、网络栈 | 底层硬件抽象和系统服务 |
|
|||
|
|
|
|||
|
|
> [!tip] Dalvik vs ART
|
|||
|
|
> - **Dalvik**:Android 4.4之前使用,基于JIT(Just-In-Time)编译
|
|||
|
|
> - **ART**:Android 5.0开始替代Dalvik,使用AOT(Ahead-Of-Time)编译,运行更快但安装更慢
|
|||
|
|
|
|||
|
|
### 2. 四大组件
|
|||
|
|
|
|||
|
|
Android应用由四大核心组件构成:
|
|||
|
|
|
|||
|
|
#### 2.1 Activity(活动)
|
|||
|
|
|
|||
|
|
Activity代表一个**用户界面屏幕**,是用户与应用交互的主要入口。
|
|||
|
|
|
|||
|
|
```java
|
|||
|
|
public class MainActivity extends AppCompatActivity {
|
|||
|
|
@Override
|
|||
|
|
protected void onCreate(Bundle savedInstanceState) {
|
|||
|
|
super.onCreate(savedInstanceState);
|
|||
|
|
setContentView(R.layout.activity_main);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 2.2 Service(服务)
|
|||
|
|
|
|||
|
|
Service在**后台**运行,没有用户界面。适合执行长时间运行的操作(如音乐播放、文件下载)。
|
|||
|
|
|
|||
|
|
两种启动方式:
|
|||
|
|
- **Started Service**:通过startService()启动,独立运行
|
|||
|
|
- **Bound Service**:通过bindService()绑定,提供客户端-服务器接口
|
|||
|
|
|
|||
|
|
#### 2.3 ContentProvider(内容提供者)
|
|||
|
|
|
|||
|
|
ContentProvider用于**跨应用数据共享**。它封装了数据访问接口,其他应用通过ContentResolver来查询和修改数据。
|
|||
|
|
|
|||
|
|
```java
|
|||
|
|
// 在AndroidManifest.xml中注册
|
|||
|
|
<provider
|
|||
|
|
android:name=".MyContentProvider"
|
|||
|
|
android:authorities="com.example.myprovider"
|
|||
|
|
android:exported="true" />
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
> [!question] 为什么需要ContentProvider而不是直接共享数据库?
|
|||
|
|
> ContentProvider提供了统一的数据访问接口和权限控制机制。直接共享数据库会暴露数据结构细节,且难以控制访问权限。
|
|||
|
|
|
|||
|
|
#### 2.4 BroadcastReceiver(广播接收器)
|
|||
|
|
|
|||
|
|
BroadcastReceiver用于接收和响应**系统或应用广播**,实现组件间的松耦合通信。
|
|||
|
|
|
|||
|
|
配置方式有两种:
|
|||
|
|
|
|||
|
|
**XML静态注册**:
|
|||
|
|
```xml
|
|||
|
|
<receiver android:name=".MyReceiver">
|
|||
|
|
<intent-filter>
|
|||
|
|
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
|||
|
|
</intent-filter>
|
|||
|
|
</receiver>
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**代码动态注册**:
|
|||
|
|
```java
|
|||
|
|
IntentFilter filter = new IntentFilter("com.example.MY_ACTION");
|
|||
|
|
registerReceiver(new MyReceiver(), filter);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 3. Activity生命周期
|
|||
|
|
|
|||
|
|
Activity的生命周期是Android开发的基础知识点:
|
|||
|
|
|
|||
|
|
```mermaid
|
|||
|
|
stateDiagram-v2
|
|||
|
|
[*] --> Created
|
|||
|
|
Created --> Started: onCreate -> onStart
|
|||
|
|
Started --> Running: onResume
|
|||
|
|
Running --> Paused: onPause
|
|||
|
|
Paused --> Running: onResume
|
|||
|
|
Paused --> Stopped: onStop
|
|||
|
|
Stopped --> Started: onRestart -> onStart
|
|||
|
|
Stopped --> Created: onDestroy
|
|||
|
|
Running --> Stopped: onStop
|
|||
|
|
Paused --> Created: onDestroy
|
|||
|
|
Created --> [*]: onDestroy
|
|||
|
|
|
|||
|
|
note right of Created: Activity created
|
|||
|
|
note right of Started: Visible but not focused
|
|||
|
|
note right of Running: Foreground, interactive
|
|||
|
|
note right of Paused: Partially obscured
|
|||
|
|
note right of Stopped: Fully hidden
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
| 生命周期方法 | 调用时机 | 说明 |
|
|||
|
|
|-------------|----------|------|
|
|||
|
|
| onCreate() | Activity首次创建 | 初始化界面、绑定数据 |
|
|||
|
|
| onStart() | Activity变为可见 | 准备显示 |
|
|||
|
|
| onResume() | Activity获得焦点 | 可与用户交互 |
|
|||
|
|
| onPause() | Activity失去焦点 | 保存临时数据(秒级) |
|
|||
|
|
| onStop() | Activity完全不可见 | 释放资源 |
|
|||
|
|
| onDestroy() | Activity被销毁 | 最终清理 |
|
|||
|
|
| onRestart() | 从Stopped重新启动 | 不会直接到onCreate |
|
|||
|
|
|
|||
|
|
> [!warning] onPause()中不要做耗时操作
|
|||
|
|
> onPause()执行完毕后,新的Activity才会启动。如果在onPause()中做网络请求或大量数据处理,会导致界面切换卡顿。耗时操作应该放到onStop()或异步任务中。
|
|||
|
|
|
|||
|
|
### 4. Intent数据传递
|
|||
|
|
|
|||
|
|
Intent是Android中组件间通信的核心机制,用于启动Activity、Service和发送广播。
|
|||
|
|
|
|||
|
|
**传递数据的两种方式**:
|
|||
|
|
|
|||
|
|
**Serializable**(Java标准序列化):
|
|||
|
|
```java
|
|||
|
|
// 发送端
|
|||
|
|
Intent intent = new Intent(this, TargetActivity.class);
|
|||
|
|
intent.putExtra("user", (Serializable) userObj);
|
|||
|
|
startActivity(intent);
|
|||
|
|
|
|||
|
|
// 接收端
|
|||
|
|
User user = (User) getIntent().getSerializableExtra("user");
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**Parcelable**(Android特有序列化,性能更好):
|
|||
|
|
```java
|
|||
|
|
// 发送端
|
|||
|
|
intent.putExtra("user", (Parcelable) userObj);
|
|||
|
|
|
|||
|
|
// 接收端
|
|||
|
|
User user = getIntent().getParcelableExtra("user");
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
| 比较 | Serializable | Parcelable |
|
|||
|
|
|------|-------------|------------|
|
|||
|
|
| 性能 | 慢(使用反射) | 快(手动实现) |
|
|||
|
|
| 实现 | 简单(实现接口即可) | 复杂(需实现writeToParcel) |
|
|||
|
|
| 用途 | 临时存储、简单对象 | Activity间频繁传递 |
|
|||
|
|
| 开销 | 产生大量临时对象 | 内存开销小 |
|
|||
|
|
|
|||
|
|
### 5. startActivityForResult
|
|||
|
|
|
|||
|
|
当一个Activity需要从另一个Activity**获取返回数据**时,使用startActivityForResult:
|
|||
|
|
|
|||
|
|
```java
|
|||
|
|
// 启动方
|
|||
|
|
Intent intent = new Intent(this, SecondActivity.class);
|
|||
|
|
startActivityForResult(intent, REQUEST_CODE);
|
|||
|
|
|
|||
|
|
// 接收返回数据
|
|||
|
|
@Override
|
|||
|
|
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
|||
|
|
if (requestCode == REQUEST_CODE && resultCode == RESULT_OK) {
|
|||
|
|
String result = data.getStringExtra("result");
|
|||
|
|
// 处理返回数据
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 被启动方设置返回数据
|
|||
|
|
Intent resultIntent = new Intent();
|
|||
|
|
resultIntent.putExtra("result", "hello from second");
|
|||
|
|
setResult(RESULT_OK, resultIntent);
|
|||
|
|
finish();
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 6. SQLite数据类型
|
|||
|
|
|
|||
|
|
Android内置SQLite数据库,支持以下5种数据类型:
|
|||
|
|
|
|||
|
|
| 数据类型 | 说明 |
|
|||
|
|
|----------|------|
|
|||
|
|
| NULL | 空值 |
|
|||
|
|
| INTEGER | 整数 |
|
|||
|
|
| REAL | 浮点数 |
|
|||
|
|
| TEXT | 文本字符串 |
|
|||
|
|
| BLOB | 二进制大对象 |
|
|||
|
|
|
|||
|
|
> [!warning] SQLite没有VARCHAR类型
|
|||
|
|
> SQLite使用动态类型系统,TEXT类型可以存储任意长度的字符串,不需要指定VARCHAR(n)。但创建表时写VARCHAR也是合法的(会被忽略长度约束)。
|
|||
|
|
|
|||
|
|
### 7. UI布局
|
|||
|
|
|
|||
|
|
Android支持多种布局方式:
|
|||
|
|
|
|||
|
|
| 布局类型 | 特点 | 适用场景 |
|
|||
|
|
|----------|------|----------|
|
|||
|
|
| **LinearLayout** | 线性排列(水平/垂直) | 简单的行列排列 |
|
|||
|
|
| **RelativeLayout** | 相对定位 | 复杂的相对位置关系 |
|
|||
|
|
| **FrameLayout** | 层叠排列,后面的元素覆盖前面 | 重叠界面、帧动画 |
|
|||
|
|
|
|||
|
|
**SimpleAdapter**用于为ListView等列表控件提供数据:
|
|||
|
|
|
|||
|
|
```java
|
|||
|
|
// 数据源:List<Map<String, Object>>
|
|||
|
|
List<Map<String, Object>> data = new ArrayList<>();
|
|||
|
|
Map<String, Object> item = new HashMap<>();
|
|||
|
|
item.put("title", "标题");
|
|||
|
|
item.put("image", R.drawable.icon);
|
|||
|
|
data.add(item);
|
|||
|
|
|
|||
|
|
// 创建适配器
|
|||
|
|
SimpleAdapter adapter = new SimpleAdapter(
|
|||
|
|
this,
|
|||
|
|
data,
|
|||
|
|
R.layout.list_item,
|
|||
|
|
new String[]{"title", "image"}, // 数据键
|
|||
|
|
new int[]{R.id.tvTitle, R.id.ivIcon} // 视图ID
|
|||
|
|
);
|
|||
|
|
listView.setAdapter(adapter);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
> [!question] SimpleAdapter的数据映射List<Map>中,Map的key和value分别对应什么?
|
|||
|
|
> key是字符串类型的字段名(如"title"),value是该字段的值(如"标题"文本)。适配器通过key从Map中取值,然后绑定到对应的视图控件上。
|
|||
|
|
|
|||
|
|
### 8. 权限管理
|
|||
|
|
|
|||
|
|
Android 7.0将权限分为四种保护级别:
|
|||
|
|
|
|||
|
|
| 权限级别 | 说明 | 安装行为 |
|
|||
|
|
|----------|------|----------|
|
|||
|
|
| **normal** | 低风险权限(如网络访问) | 自动授予 |
|
|||
|
|
| **dangerous** | 高风险权限(如摄像头、位置) | 需要用户确认 |
|
|||
|
|
| **signature** | 只有与应用签名相同的应用才能获得 | 自动授予 |
|
|||
|
|
| **signatureOrSystem** | 签名相同或系统应用才能获得 | 自动授予 |
|
|||
|
|
|
|||
|
|
权限声明方式(AndroidManifest.xml):
|
|||
|
|
```xml
|
|||
|
|
<uses-permission android:name="android.permission.CAMERA" />
|
|||
|
|
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
> [!warning] Android 6.0+运行时权限
|
|||
|
|
> 从Android 6.0开始,dangerous权限需要在运行时动态申请,而不仅仅在Manifest中声明。但signature和normal权限仍然在安装时自动授予。
|
|||
|
|
|
|||
|
|
### 9. SharedPreferences
|
|||
|
|
|
|||
|
|
SharedPreferences是Android提供的轻量级键值对存储机制:
|
|||
|
|
|
|||
|
|
```java
|
|||
|
|
// 保存数据
|
|||
|
|
SharedPreferences prefs = getSharedPreferences("mydata", MODE_PRIVATE);
|
|||
|
|
SharedPreferences.Editor editor = prefs.edit();
|
|||
|
|
editor.putString("username", "admin");
|
|||
|
|
editor.putInt("age", 25);
|
|||
|
|
editor.apply(); // 异步写入
|
|||
|
|
|
|||
|
|
// 读取数据
|
|||
|
|
String name = prefs.getString("username", "default");
|
|||
|
|
int age = prefs.getInt("age", 0);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
> [!warning] 默认不能跨应用共享
|
|||
|
|
> MODE_PRIVATE表示该SharedPreferences文件只有当前应用可以访问。如果需要跨应用共享数据,应该使用ContentProvider。
|
|||
|
|
|
|||
|
|
### 10. res vs assets
|
|||
|
|
|
|||
|
|
| 比较 | res | assets |
|
|||
|
|
|------|-----|--------|
|
|||
|
|
| 引用方式 | 通过R.java自动生成的ID | 通过AssetManager按文件名访问 |
|
|||
|
|
| 子目录 | 有结构化子目录(drawable, layout等) | 无结构,可自由组织 |
|
|||
|
|
| 自动优化 | 编译时会被压缩/优化 | 原样保留 |
|
|||
|
|
| 文件名限制 | 只能用小写字母、数字、下划线 | 无限制 |
|
|||
|
|
|
|||
|
|
```java
|
|||
|
|
// res资源引用
|
|||
|
|
setContentView(R.layout.activity_main);
|
|||
|
|
ImageView iv = findViewById(R.id.imageView);
|
|||
|
|
iv.setImageResource(R.drawable.icon);
|
|||
|
|
|
|||
|
|
// assets资源访问
|
|||
|
|
InputStream is = getAssets().open("data/config.json");
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 11. 单例模式
|
|||
|
|
|
|||
|
|
单例模式确保一个类只有一个实例:
|
|||
|
|
|
|||
|
|
```java
|
|||
|
|
public class DatabaseHelper {
|
|||
|
|
private static volatile DatabaseHelper instance;
|
|||
|
|
|
|||
|
|
// 私有构造函数,防止外部实例化
|
|||
|
|
private DatabaseHelper() {
|
|||
|
|
// 初始化数据库
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public static DatabaseHelper getInstance() {
|
|||
|
|
if (instance == null) {
|
|||
|
|
synchronized (DatabaseHelper.class) {
|
|||
|
|
if (instance == null) {
|
|||
|
|
instance = new DatabaseHelper();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return instance;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
> [!tip] 双重检查锁定(Double-Checked Locking)
|
|||
|
|
> 单例模式中使用volatile + synchronized实现线程安全的懒加载。volatile防止指令重排序,synchronized保证只创建一次实例。
|
|||
|
|
|
|||
|
|
## 关联笔记
|
|||
|
|
- [[嵌入式系统/试题册/index|试题册索引]]
|