安卓期末复习


§1 Android 开发环境相关

1. Android / API / SDK 概念

术语 含义
Android Google 主导的基于 Linux 内核的移动操作系统,采用分层架构(Linux Kernel → HAL → Native Libraries / Android Runtime → Framework API → System Apps)
API Level 框架 API 的整型版本号。每个 Android 版本对应一个 API Level(如 Android 13 = API 33)。minSdkVersion 决定最低兼容版本,targetSdkVersion 决定行为适配版本
SDK Software Development Kit,含 android.jar(Framework API)、build-tools(aapt/d8/zipalign)、platform-tools(adb/fastboot)、模拟器镜像、源码文档

2. Android 应用程序开发环境

  • IDE: Android Studio(基于 IntelliJ IDEA)
  • 构建工具链: Gradle → aapt2 编译资源 → javac/kotlinc → d8 字节码 → apksigner 签名
  • 调试 : adb(Android Debug Bridge),通过 USB/WiFi 连接设备,adb logcatadb installadb shell
  • 虚拟机: AVD(Android Virtual Device),需配置 CPU/ABI(x86_64 或 arm64-v8a)、系统镜像、内存/存储大小

3. AndroidManifest.xml 作用

manifest 是每个 Android 应用的入口声明文件,负责:

  • 包名声明 : package="com.example.app"(唯一标识)
  • 组件注册 : 四大组件(Activity、Service、BroadcastReceiver、ContentProvider)必须在此声明,否则运行时报 ActivityNotFoundException
  • 权限声明 : <uses-permission> 声明需要申请的权限,<permission> 自定义权限
  • 硬件特性 : <uses-feature> 声明需要的硬件(如摄像头、GPS)
  • 应用入口 : <intent-filter> 中声明 MAIN + LAUNCHER 的 Activity 作为桌面图标入口
  • 最低 SDK 版本 : <uses-sdk android:minSdkVersion="26" android:targetSdkVersion="34" />

4. Gradle Scripts

  • settings.gradle : 声明项目包含的模块名 include ':app'
  • build.gradle(项目级): 配置全局仓库(google()/mavenCentral())和 AGP(Android Gradle Plugin)版本
  • build.gradle(模块级): 核心构建配置
groovy 复制代码
android {
    namespace "com.example.app"       // 应用命名空间
    compileSdk 34                     // 编译 SDK 版本
    defaultConfig {
        applicationId "com.example.app"  // APP 唯一 ID
        minSdk 26                         // 最低兼容版本
        targetSdk 34                      // 目标适配版本
        versionCode 1                     // 内部版本号
        versionName "1.0"                 // 外部版本名称
    }
}
dependencies {
    implementation "androidx.core:core-ktx:1.12.0"   // 依赖
    testImplementation "junit:junit:4.13.2"          // 测试依赖
}
  • implementation vs api: implementation 依赖不传递,api 依赖传递
  • compileOnly: 仅编译期有效,不打包进 APK
  • annotationProcessor: 注解处理器依赖

§2 Activity 与 Intent

1. Activity 生命周期

标准 7 个回调:

复制代码
onCreate() → onStart() → onResume() → [Activity 运行中]
                                            ↓
                                      onPause()
                                      /        \
                              onResume()    onStop()
                                            /      \
                                    onRestart()  onDestroy()
回调 时机 能做什么
onCreate() Activity 首次创建 setContentView() 加载布局,初始化变量,findViewById
onStart() 即将可见 注册监听,UI 可见前准备
onResume() 前台获取焦点 开启动画、相机、传感器等前台资源
onPause() 失去焦点(如弹框覆盖) 保存数据、暂停动画/传感器(必须快速完成
onStop() 完全不可见 释放重量级资源
onRestart() 从 stop→start 重新加载数据
onDestroy() Activity 销毁 最终清理,解除所有绑定

常见场景走了哪些回调:

  • A 启动 B:A.onPause → B.onCreate → B.onStart → B.onResume → A.onStop
  • 按 Home 键:onPause → onStop
  • 旋转屏幕:onPause → onStop → onDestroy → onCreate → onStart → onResume(默认重建)

2. Intent 组件作用

Intent 是 Android 四大组件之间的通信信使:

作用 说明
页面跳转 startActivity(intent) 启动另一个 Activity
数据传递 putExtra("key", value) 携带数据,目标页用 getStringExtra("key") 接收
启动 Service startService(intent)bindService(intent, ...)
发送广播 sendBroadcast(intent)
调用系统功能 拨号 ACTION_DIAL、拍照 ACTION_IMAGE_CAPTURE、打开网页 ACTION_VIEW

显式 Intent vs 隐式 Intent:

  • 显式:直接指定目标组件类名 Intent(this, TargetActivity::class.java)
  • 隐式:通过 action/data/category 匹配,系统找到合适的组件处理

3. Intent 实现页面跳转的方法

java 复制代码
// 方式一:显式 Intent
Intent intent = new Intent(MainActivity.this, SecondActivity.class);
intent.putExtra("username", "张三");
startActivity(intent);

// 方式二:隐式 Intent
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("https://www.baidu.com"));
startActivity(intent);

// 方式三:带返回值的跳转
Intent intent = new Intent(this, EditActivity.class);
startActivityForResult(intent, REQUEST_CODE);  // 已废弃,改用 ActivityResultLauncher

// 方式四:在 Intent 中指定 Action 和 Category
Intent intent = new Intent("com.example.MY_ACTION");
intent.addCategory(Intent.CATEGORY_DEFAULT);
startActivity(intent);

4. 组件声明(清单文件)

四大组件必须全部在 AndroidManifest.xml 中声明,否则抛出异常:

xml 复制代码
<activity android:name=".MainActivity" android:exported="true">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>
<service android:name=".MyService" />
<receiver android:name=".MyReceiver" android:exported="true" />
<provider android:name=".MyProvider" android:authorities="com.example.provider" />
  • android:exported: Android 12+ 强制声明,表示是否允许其他应用访问
  • 只有动态注册的 BroadcastReceiver 可以不写 manifest

§4 Android 界面布局 / 控件

1. 常用布局容器

布局 特点
LinearLayout 线性排列,orientation="vertical" 垂直 / horizontal 水平
RelativeLayout 相对布局,控件相对于父容器或兄弟控件定位
ConstraintLayout 约束布局(Google 推荐默认),通过约束关系定位,扁平化
FrameLayout 帧布局,子控件层叠堆放,常用作 fragment 容器
TableLayout 表格布局,配合 TableRow 使用

2. TableLayout → TableRow 的结构

TableLayout 类似 HTML <table>,每行是一个 TableRow:

xml 复制代码
<TableLayout ...>
    <TableRow android:layout_height="wrap_content">
        <TextView android:text="姓名" android:layout_column="0" />
        <EditText android:layout_column="1" android:layout_span="2" />
    </TableRow>
    <TableRow ...>
        <Button android:text="确定" />
    </TableRow>
</TableLayout>

关键属性:

  • android:stretchColumns:拉伸指定列(如 "0" 拉伸第一列)
  • android:shrinkColumns:收缩指定列
  • android:layout_column:指定控件所在列
  • android:layout_span:跨列数量

3. 相对布局 RelativeLayout

控件位置通过相对关系描述:

属性 含义
android:layout_alignParentTop/Bottom/Left/Right 贴父容器边缘
android:layout_centerInParent 父容器正中央
android:layout_above="@id/btn" 在某个控件上方
android:layout_below="@id/btn" 在某个控件下方
android:layout_toLeftOf / layout_toRightOf 在某个控件左/右侧
android:layout_alignTop="@id/btn" 与某个控件顶对齐
android:layout_alignBaseline="@id/tv" 文字基线对齐

ID 的声明方式:android:id="@+id/my_button" → 在 R.java 中生成引用。

4. 线性布局 LinearLayout

  • 垂直排列 : android:orientation="vertical" → 控件从上到下依次排列
  • 水平排列 : android:orientation="horizontal" → 控件从左到右依次排列
  • 权重分配 : android:layout_weight="1",按比例分配剩余空间(weight 越大占比越大)

注意 : 使用 weight 时,对应方向的宽/高应设为 0dp 以优化性能。

5. 绝对布局 AbsoluteLayout

已废弃。通过 x/y 坐标精确放置控件,无法适配不同屏幕尺寸,不推荐使用

6. 通用组件属性

属性 含义
android:layout_width 宽度:match_parent(填满父容器)或 wrap_content(包裹内容)或具体 dp 值
android:layout_height 高度,同上
android:id 组件唯一标识 @+id/xxx
android:padding 内边距(控件内容到边框)
android:layout_margin 外边距(控件边框到相邻元素)
android:gravity 内容对齐方式
android:layout_gravity 控件在父容器中的对齐方式
android:visibility visible / invisible(占位不可见) / gone(不占位)

§5 控件与事件

1. 常用控件

控件 作用
TextView 显示文本,android:text="文本"android:textSize="16sp"android:textColor="#000"
Button 按钮,继承自 TextView,常用 android:onClick="methodName"
EditText 输入框,android:hint="请输入" 占位文字,android:inputType="textPassword" 输入类型
ImageView 显示图片,android:src="@drawable/ic_launcher"android:scaleType="centerCrop"
CheckBox 复选框,isChecked() 判断勾选状态
RadioButton 单选按钮,放在 RadioGroup 中互斥
Spinner 下拉选择框,绑定 Adapter 设置选项
ListView 列表控件,通过 Adapter 绑定数据源,配合 setOnItemClickListener 处理点击

2. 事件处理方法

方式一:XML 中声明 onClick(最简单)

xml 复制代码
<Button android:onClick="doLogin" />
java 复制代码
public void doLogin(View view) {
    // 在 Activity 中定义,方法名需与 XML 一致,参数固定为 View
}

方式二:匿名内部类 setOnClickListener

java 复制代码
button.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        // 处理点击
    }
});

方式三:Lambda(Java 8+ / Kotlin)

java 复制代码
button.setOnClickListener(v -> { /* 处理点击 */ });

方式四:Activity 实现 View.OnClickListener 接口

java 复制代码
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    button.setOnClickListener(this);
    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.btn_login: // ...
        }
    }
}

3. dp / px / sp 单位

单位 含义 使用场景
px 像素点 不推荐写死,不同密度设备显示大小不同
dp (dip) 密度无关像素,1dp = 1px@160dpi 布局宽高、间距,推荐
sp 比例无关像素,与 dp 类似但受系统字体大小设置影响 文字大小专用

换算:px = dp × (dpi / 160)


§6 菜单与对话框

1. 菜单类型与绘制

Android 标准三类菜单:

类型 触发方式 适用场景
选项菜单 OptionsMenu 按 Menu 键或 ActionBar 三点图标 全局操作(设置、搜索)
上下文菜单 ContextMenu 长按某个 View 针对特定控件的操作(删除、编辑)
弹出菜单 PopupMenu 点击触发 锚定到某个 View 弹出

选项菜单创建(重写两个方法):

java 复制代码
// 1. 加载菜单布局
@Override
public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.main_menu, menu);  // 从 XML 加载
    return true;
}

// 2. 处理菜单点击
@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
        case R.id.action_add: /* ... */ return true;
        default: return super.onOptionsItemSelected(item);
    }
}

菜单布局文件 res/menu/main_menu.xml

xml 复制代码
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@+id/action_add" android:title="添加" android:icon="@drawable/ic_add" />
    <item android:id="@+id/action_search" android:title="搜索" android:showAsAction="ifRoom" />
</menu>

2. Dialog / AlertDialog

创建 AlertDialog:

java 复制代码
// 使用 Builder 模式
new AlertDialog.Builder(this)
    .setTitle("提示")                          // 标题
    .setMessage("确定删除吗?")                 // 内容
    .setIcon(R.drawable.ic_warning)            // 图标
    .setPositiveButton("确定", (dialog, which) -> {  // 确定按钮
        // 执行删除
    })
    .setNegativeButton("取消", null)            // 取消按钮
    .setNeutralButton("稍后", null)             // 中间按钮
    .setCancelable(true)                        // 点击外部是否消失
    .create()
    .show();

关键点:

  • 必须通过 Builder 构造,不能直接 new AlertDialog()
  • setTitle 设置标题,setMessage 设置内容,setPositiveButton/NegativeButton/NeutralButton 三个按钮
  • 调用 .show() 才能显示

3. Toast 提示框

java 复制代码
// 标准用法
Toast.makeText(context, "提示文字", Toast.LENGTH_SHORT).show();

// 参数说明
// 参数1: Context(Activity 中直接 this)
// 参数2: CharSequence 文字内容
// 参数3: 显示时长 Toast.LENGTH_SHORT(约2秒) 或 Toast.LENGTH_LONG(约3.5秒)

// 自定义位置
Toast toast = Toast.makeText(this, "居中提示", Toast.LENGTH_SHORT);
toast.setGravity(Gravity.CENTER, 0, 0);
toast.show();

注意:必须调用 .show() 才显示!


§8 Android 消息机制

1. Message 与 Handler 定义

作用
Handler 消息处理器,负责发送 Message 到 MessageQueue在目标线程中处理 Message
Message 消息载体,包含 what(int 标识)、arg1/arg2(int 参数)、obj(Object 数据)
MessageQueue 消息队列,以单链表存储 Message,按时间排序
Looper 消息循环器,不断从 MessageQueue 中取 Message 分发给对应 Handler

工作机制:

复制代码
子线程 → Handler.sendMessage(msg) → MessageQueue.enqueueMessage()
                                        ↓
                    主线程 ← Looper.loop() 循环取出 ← handleMessage(msg)

2. 创建线程时的使用方法

java 复制代码
// 步骤1: 在主线程创建 Handler
Handler handler = new Handler(Looper.getMainLooper()) {
    @Override
    public void handleMessage(Message msg) {
        // 此方法运行在主线程,可安全更新 UI
        switch (msg.what) {
            case 1:
                textView.setText((String) msg.obj);
                break;
        }
    }
};

// 步骤2: 在子线程发送消息
new Thread(() -> {
    // 模拟耗时操作
    String data = fetchDataFromNetwork();

    Message msg = Message.obtain();  // 推荐用 obtain() 复用,比 new 高效
    msg.what = 1;                    // 消息标识
    msg.obj = data;                  // 携带数据
    handler.sendMessage(msg);        // 发送到主线程处理

    // 或使用 sendEmptyMessage(what) 发送空消息
    // handler.sendEmptyMessage(2);
}).start();

Handler.post() 快捷方式:

java 复制代码
new Thread(() -> {
    String result = doHeavyWork();
    handler.post(() -> textView.setText(result));  // 直接抛 Runnable 到主线程
}).start();

3. 线程通信 / 异步处理的含义

为什么需要 Handler?

  • Android 规定:只有主线程(UI 线程)才能更新 UI 组件
  • 子线程做网络请求、数据库查询等耗时操作,完成后通过 Handler 将结果抛回主线程更新 UI

这就是典型的"线程通信 / 异步处理"模式:子线程干活,主线程更新界面。


§9 网络编程

1. URL 相关基础

java 复制代码
URL url = new URL("https://api.example.com/data?page=1");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");              // 请求方式
conn.setConnectTimeout(5000);              // 连接超时 5s
conn.setReadTimeout(5000);                 // 读取超时 5s

int code = conn.getResponseCode();         // 响应码 200/404/500
if (code == 200) {
    InputStream is = conn.getInputStream();
    // 读取流 → String
    BufferedReader reader = new BufferedReader(new InputStreamReader(is));
    StringBuilder sb = new StringBuilder();
    String line;
    while ((line = reader.readLine()) != null) {
        sb.append(line);
    }
    String result = sb.toString();
}
conn.disconnect();

注意:网络请求必须放在子线程,Android 主线程禁止网络操作(NetworkOnMainThreadException)。

2. Socket 网络连接

java 复制代码
// 客户端 Socket
Socket socket = new Socket("192.168.1.100", 8888);  // IP + 端口
OutputStream out = socket.getOutputStream();
PrintWriter writer = new PrintWriter(out);
writer.println("Hello Server");
writer.flush();

InputStream in = socket.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
String response = reader.readLine();

socket.close();
  • Socket 是基于 TCP 的长连接,适合即时通讯等场景
  • 与 HTTP 不同,Socket 可以双向实时通信

3. GET 与 POST 请求

GET POST
参数位置 URL 后面 ?key=value&... 请求体中
数据量 受 URL 长度限制(~2KB) 无限制
安全性 参数暴露在 URL 中 相对安全
语义 获取数据 提交数据

GET 请求:

java 复制代码
URL url = new URL("https://api.example.com/search?keyword=Android");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");

POST 请求:

java 复制代码
URL url = new URL("https://api.example.com/login");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("POST");
conn.setDoOutput(true);                              // 允许输出
conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");

// 写入请求体
OutputStream os = conn.getOutputStream();
os.write("username=admin&password=123".getBytes());
os.flush();
os.close();

4. 获取服务端数据 / HTTP 请求完整流程

复制代码
1. 创建 URL 对象(含地址和参数)
2. openConnection() 获取 HttpURLConnection
3. 设置请求方式(GET/POST)、超时、请求头
4. POST 需 setDoOutput(true) 并写入请求体
5. getResponseCode() 检查响应码
6. getInputStream() 读取响应数据
7. 在子线程中执行上述步骤,通过 Handler 将结果抛回主线程
8. 在 AndroidManifest.xml 中声明 <uses-permission android:name="android.permission.INTERNET" />

常见 HTTP 状态码: 200 OK、301 Moved、404 Not Found、500 Server Error


补充资料索引

资料 覆盖内容
\[Android补充知识点] res 目录细节、Intent 6 属性+Bundle、百分比布局、FrameLayout 前景、ImageButton/ToggleButton、EditText 补充、TabHost、ScrollView、RecyclerView、SubMenu、Toast 全方法、线程创建两种方式
\[例题套卷6] 补充知识点选择题+填空+简答+编程,侧重 RecyclerView、Bundle、FrameLayout
\[例题套卷7] 补充知识点第二轮,侧重 百分比布局、TabHost、Toast 方法、RecyclerView vs ListView