Ubuntu 22.04中的Java与Android开发环境 - 详细知识点总结
1. Java开发
1.1 Java的特点
平台无关性:
- Java程序编译成字节码(.class文件)
- 通过JVM(Java虚拟机)在不同平台上运行相同的字节码
- "一次编写,到处运行"(Write Once, Run Anywhere)
面向对象:
- 封装:将数据和操作数据的方法绑定在一起
- 继承:子类继承父类的特性和行为
- 多态:同一操作作用于不同对象产生不同行为
内存管理:
- 自动垃圾回收(GC)机制
- 开发者无需手动释放内存
- 减少内存泄漏风险
丰富的标准库:
- 集合框架(Collections Framework)
- 并发工具包(java.util.concurrent)
- I/O和NIO
- 网络编程API
- 反射机制
安全性:
- 沙箱安全模型
- 字节码验证
- 安全管理器
- 加密API
多线程支持:
- 内置多线程API
- 同步机制
- 线程池
- Future/Promise模式
1.2 Java体系
| 组件 | 描述 | 用途 |
|---|---|---|
| JDK (Java Development Kit) | Java开发工具包 | 编写、编译和运行Java程序 |
| JRE (Java Runtime Environment) | Java运行环境 | 仅运行Java程序 |
| JVM (Java Virtual Machine) | Java虚拟机 | 执行Java字节码 |
| Java SE (Standard Edition) | 标准版 | 桌面和服务器应用开发 |
| Java EE (Enterprise Edition) | 企业版 | 企业级Web应用和分布式系统 |
| Java ME (Micro Edition) | 微型版 | 嵌入式和移动设备开发 |
JDK主要组件:
javac: Java编译器,将.java源文件编译成.class字节码java: Java启动器,运行编译后的Java程序javadoc: 生成API文档jar: 打包Java类文件jdb: Java调试器jconsole: 监控JVM性能jvisualvm: 可视化性能分析工具
1.3 安装JDK
1.3.1 OpenJDK安装 (推荐)
bash
# 1. 更新软件包列表
sudo apt update
# 2. 安装OpenJDK 17 (Ubuntu 22.04默认版本)
sudo apt install openjdk-17-jdk -y
# 3. 验证安装
java -version
# 预期输出:
# openjdk version "17.0.8" 2023-07-18
# OpenJDK Runtime Environment (build 17.0.8+7-Ubuntu-122.04)
# OpenJDK 64-Bit Server VM (build 17.0.8+7-Ubuntu-122.04, mixed mode, sharing)
javac -version
# 预期输出: javac 17.0.8
1.3.2 Oracle JDK安装 (可选)
bash
# 1. 添加Oracle JDK PPA
sudo add-apt-repository ppa:linuxuprising/java
sudo apt update
# 2. 安装Oracle JDK 17
sudo apt install oracle-java17-installer -y
# 3. 接受许可协议 (自动)
sudo apt install oracle-java17-set-default -y
# 4. 验证安装
java -version
# 预期输出应显示Oracle JDK版本
1.3.3 配置环境变量
Ubuntu 22.04通常自动配置JDK环境变量,但可以手动验证或修改:
bash
# 1. 查找Java安装路径
sudo update-alternatives --config java
# 输出示例: /usr/lib/jvm/java-17-openjdk-amd64/bin/java
# 2. 设置JAVA_HOME (通常已自动设置,可验证)
echo $JAVA_HOME
# 如果为空,编辑~/.bashrc或/etc/environment
# 添加: export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64
-- 对于大数据环境,设置 JAVA_HOME 非常重要。您可以将以下行添加到您的 ~/.bashrc 或 ~/.profile 文件中来设置它:
export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64
export PATH=$JAVA_HOME/bin:$PATH
# 3. 使配置生效
source ~/.bashrc
# 或
source /etc/environment
# 4. 验证JAVA_HOME
echo $JAVA_HOME
# 预期输出: /usr/lib/jvm/java-17-openjdk-amd64
1.4 管理Java版本
1.4.1 安装多个Java版本
bash
# 1. 安装OpenJDK 8
sudo apt install openjdk-8-jdk -y
# 2. 安装OpenJDK 11
sudo apt install openjdk-11-jdk -y
# 3. 验证所有已安装版本
update-java-alternatives --list
# 输出示例:
# java-1.11.0-openjdk-amd64 1111 /usr/lib/jvm/java-1.11.0-openjdk-amd64
# java-1.17.0-openjdk-amd64 1711 /usr/lib/jvm/java-1.17.0-openjdk-amd64
# java-1.8.0-openjdk-amd64 1081 /usr/lib/jvm/java-1.8.0-openjdk-amd64
1.4.2 切换Java版本
bash
# 1. 交互式选择Java版本
sudo update-alternatives --config java
# 将显示所有Java版本列表,输入对应数字选择
# 2. 设置默认javac版本
sudo update-alternatives --config javac
# 3. 批量切换 (使用update-java-alternatives)
# 切换到Java 17
sudo update-java-alternatives --set java-1.17.0-openjdk-amd64
# 切换到Java 11
sudo update-java-alternatives --set java-1.11.0-openjdk-amd64
# 切换到Java 8
sudo update-java-alternatives --set java-1.8.0-openjdk-amd64
1.4.3 项目级Java版本管理
使用sdkman管理多版本:
bash
# 1. 安装sdkman
curl -s "https://get.sdkman.io" | bash
source "$HOME/.sdkman/bin/sdkman-init.sh"
# 2. 列出可用Java版本
sdk list java
# 3. 安装特定版本
sdk install java 17.0.8-open
sdk install java 11.0.19-open
sdk install java 8.0.372-open
# 4. 为特定目录设置Java版本
# 创建~/.sdkmanrc文件
echo "java=17.0.8-open" > ~/.sdkmanrc
# 或使用别名
sdk use java 11.0.19-open
Maven项目中的Java版本配置:
xml
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.10.1</version>
<configuration>
<source>17</source> <!-- 源代码使用的Java版本 -->
<target>17</target> <!-- 生成的字节码目标版本 -->
<release>17</release> <!-- Java 9+ 的等效配置 -->
</configuration>
</plugin>
</plugins>
</build>
Gradle项目中的Java版本配置:
groovy
// build.gradle
plugins {
id 'java'
}
java {
toolchain {
languageVersion = JavaLanguageVersion.of(17)
}
}
tasks.withType(JavaCompile).configureEach {
options.release = 17
}
1.5 在Ubuntu 22.04上安装IntelliJ IDEA开发Java项目
1.5.1 通过JetBrains Toolbox安装 (推荐)
bash
# 1. 下载Toolbox
wget https://download.jetbrains.com/toolbox/jetbrains-toolbox-1.27.3.14802.tar.gz
tar -xzf jetbrains-toolbox-*.tar.gz
rm jetbrains-toolbox-*.tar.gz
# 2. 运行Toolbox安装程序
cd jetbrains-toolbox-*/
./jetbrains-toolbox
# 3. 在UI界面中选择IntelliJ IDEA Community或Ultimate版本安装
# 4. 安装完成后,可从应用菜单启动IntelliJ IDEA
1.5.2 通过Snap安装 (简单方式)
bash
# 1. 安装IntelliJ IDEA Community版本
sudo snap install intellij-idea-community --classic
# 2. (可选) 安装Ultimate版本
sudo snap install intellij-idea-ultimate --classic
# 3. 启动IDE
intellij-idea-community
# 或通过应用菜单启动
1.5.3 手动安装
bash
# 1. 下载IntelliJ IDEA (社区版)
wget https://download.jetbrains.com/idea/ideaIC-2023.1.3.tar.gz
# 2. 解压到/opt目录
sudo tar -xzf ideaIC-*.tar.gz -C /opt/
sudo mv /opt/idea-IC-* /opt/idea-community
# 3. 创建启动脚本
sudo ln -s /opt/idea-community/bin/idea.sh /usr/local/bin/idea
# 4. 创建桌面快捷方式
cat > ~/.local/share/applications/intellij-idea.desktop <<EOF
[Desktop Entry]
Version=1.0
Type=Application
Name=IntelliJ IDEA Community Edition
Icon=/opt/idea-community/bin/idea.png
Exec="/opt/idea-community/bin/idea.sh" %f
Comment=Develop with pleasure!
Categories=Development;IDE;
Terminal=false
StartupWMClass=jetbrains-idea-ce
EOF
# 5. 更新桌面数据库
update-desktop-database ~/.local/share/applications
# 6. 启动IDE
idea
1.5.4 配置IntelliJ IDEA
-
首次启动配置:
- 选择UI主题 (推荐Darcula暗色主题)
- 配置插件 (建议安装Maven、Gradle、Git、Lombok等)
- 配置JDK路径 (自动检测或手动指定)
- 配置Maven/Gradle设置
-
关键配置:
File > Settings > Editor > Code Style: 配置代码风格File > Settings > Build, Execution, Deployment > Build Tools: 配置构建工具File > Settings > Tools > Terminal: 配置终端,可设置默认shell为bash或zshFile > Settings > Keymap: 自定义快捷键方案
-
重要快捷键:
Ctrl+Shift+N: 快速打开文件Ctrl+Space: 基本代码补全Ctrl+Shift+Space: 智能类型感知补全Alt+Enter: 显示上下文操作Ctrl+P: 显示参数信息Ctrl+Q: 快速文档查询Shift+F6: 重命名Ctrl+Alt+L: 格式化代码
1.6 开发Java应用程序
1.6.1 创建简单Java应用
示例1: 基本控制台应用 (Hello World)
java
/**
* HelloWorld.java
* 一个简单的Java应用程序,演示基本语法和结构
*/
public class HelloWorld {
/**
* 程序入口点
* @param args 命令行参数
*/
public static void main(String[] args) {
// 打印Hello World到控制台
System.out.println("Hello, World!");
// 调用自定义方法
greetUser("Java Developer");
// 演示基本变量
int number = 42;
double pi = 3.14159;
boolean isJavaFun = true;
char grade = 'A';
String language = "Java";
// 格式化输出
System.out.printf("Number: %d, Pi: %.2f, Language: %s%n", number, pi, language);
// 条件语句示例
if (isJavaFun) {
System.out.println("Java is fun!");
} else {
System.out.println("Try harder to enjoy Java!");
}
// 循环示例
System.out.println("Counting from 1 to 5:");
for (int i = 1; i <= 5; i++) {
System.out.println("Count: " + i);
}
}
/**
* 问候用户的方法
* @param name 用户名
*/
public static void greetUser(String name) {
System.out.println("Hello, " + name + "! Welcome to Java programming.");
}
}
编译运行:
bash
# 1. 保存上面代码到HelloWorld.java
# 2. 编译
javac HelloWorld.java
# 3. 运行
java HelloWorld
# 预期输出:
# Hello, World!
# Hello, Java Developer! Welcome to Java programming.
# Number: 42, Pi: 3.14, Language: Java
# Java is fun!
# Counting from 1 to 5:
# Count: 1
# Count: 2
# Count: 3
# Count: 4
# Count: 5
1.6.2 Java核心语法知识点
数据类型:
java
// 基本数据类型
byte smallNumber = 127; // 8位有符号整数
short mediumNumber = 32767; // 16位有符号整数
int largeNumber = 2147483647; // 32位有符号整数
long hugeNumber = 9223372036854775807L; // 64位有符号整数,需要L后缀
float floatValue = 3.14f; // 32位浮点数,需要f后缀
double doubleValue = 3.1415926535; // 64位浮点数(默认)
char character = 'A'; // 16位Unicode字符
boolean flag = true; // 布尔值(true/false)
// 引用类型
String text = "Hello Java"; // 字符串
Integer wrappedInt = Integer.valueOf(42); // 包装类
Object obj = new Object(); // 通用对象
控制结构:
java
// if-else语句
int score = 85;
if (score >= 90) {
System.out.println("Grade: A");
} else if (score >= 80) {
System.out.println("Grade: B"); // 这行会被执行
} else if (score >= 70) {
System.out.println("Grade: C");
} else {
System.out.println("Grade: F");
}
// switch语句 (Java 17支持)
String day = "Monday";
switch (day) {
case "Monday", "Tuesday", "Wednesday", "Thursday", "Friday" ->
System.out.println("Weekday");
case "Saturday", "Sunday" ->
System.out.println("Weekend");
default ->
System.out.println("Invalid day");
}
// for循环
System.out.println("For loop:");
for (int i = 0; i < 5; i++) {
System.out.println("Iteration: " + i);
}
// 增强型for循环
String[] fruits = {"Apple", "Banana", "Cherry"};
System.out.println("Enhanced for loop:");
for (String fruit : fruits) {
System.out.println("Fruit: " + fruit);
}
// while循环
int count = 0;
System.out.println("While loop:");
while (count < 3) {
System.out.println("Count: " + count);
count++;
}
// do-while循环
int num = 5;
System.out.println("Do-while loop:");
do {
System.out.println("Number: " + num);
num--;
} while (num > 0);
面向对象编程:
java
/**
* Employee.java
* 演示Java的面向对象特性:封装、继承、多态
*/
// 基类
class Person {
// 封装:私有字段
private String name;
private int age;
// 构造函数
public Person(String name, int age) {
this.name = name;
this.age = age;
}
// Getter和Setter方法
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
if (age > 0) {
this.age = age;
}
}
// 方法
public void introduce() {
System.out.println("Hi, I'm " + name + ", " + age + " years old.");
}
}
// 子类:继承Person
class Employee extends Person {
private String employeeId;
private double salary;
// 构造函数
public Employee(String name, int age, String employeeId, double salary) {
super(name, age); // 调用父类构造函数
this.employeeId = employeeId;
this.salary = salary;
}
// 重写父类方法(多态)
@Override
public void introduce() {
super.introduce(); // 调用父类方法
System.out.println("Employee ID: " + employeeId + ", Salary: $" + salary);
}
// 特定于Employee的方法
public void work() {
System.out.println(getName() + " is working hard.");
}
public double getAnnualBonus() {
return salary * 0.1; // 10% bonus
}
}
// 接口
interface Workable {
void startWork();
void endWork();
}
// 实现接口
class Manager extends Employee implements Workable {
private int teamSize;
public Manager(String name, int age, String employeeId, double salary, int teamSize) {
super(name, age, employeeId, salary);
this.teamSize = teamSize;
}
@Override
public void introduce() {
super.introduce();
System.out.println("Manages a team of " + teamSize + " people.");
}
// 实现接口方法
@Override
public void startWork() {
System.out.println(getName() + " starts managing the team.");
}
@Override
public void endWork() {
System.out.println(getName() + " ends the work day.");
}
// 重写获取奖金方法
@Override
public double getAnnualBonus() {
return super.getAnnualBonus() + (teamSize * 1000); // 额外团队奖金
}
}
// 测试类
public class OOPDemo {
public static void main(String[] args) {
// 创建对象
Person person = new Person("Alice", 30);
Employee employee = new Employee("Bob", 35, "E12345", 75000.0);
Manager manager = new Manager("Charlie", 45, "M54321", 120000.0, 8);
// 多态:父类引用指向子类对象
Person[] people = {person, employee, manager};
System.out.println("=== Demonstrating Polymorphism ===");
for (Person p : people) {
p.introduce(); // 根据实际对象类型调用相应方法
System.out.println("---");
}
// 使用接口
System.out.println("\n=== Demonstrating Interface ===");
Workable workableManager = manager; // Manager is-a Workable
workableManager.startWork();
workableManager.endWork();
// 访问特定方法
System.out.println("\n=== Specific Methods ===");
employee.work();
System.out.println("Employee's annual bonus: $" + employee.getAnnualBonus());
manager.work(); // 继承自Employee
System.out.println("Manager's annual bonus: $" + manager.getAnnualBonus());
}
}
异常处理:
java
import java.io.*;
import java.util.*;
/**
* ExceptionDemo.java
* 演示Java异常处理机制
*/
public class ExceptionDemo {
/**
* 演示检查型异常 (checked exceptions)
*/
public static void readFile(String filename) {
try {
// 检查型异常:必须处理或声明抛出
FileReader fileReader = new FileReader(filename);
BufferedReader bufferedReader = new BufferedReader(fileReader);
String line;
while ((line = bufferedReader.readLine()) != null) {
System.out.println(line);
}
bufferedReader.close();
} catch (FileNotFoundException e) {
// 处理文件未找到异常
System.err.println("Error: File not found - " + filename);
e.printStackTrace();
} catch (IOException e) {
// 处理IO异常
System.err.println("Error reading file: " + filename);
e.printStackTrace();
} finally {
// 无论是否发生异常,都会执行
System.out.println("File reading attempt completed.");
}
}
/**
* 演示非检查型异常 (unchecked exceptions)
*/
public static void processArray(int[] array, int index) {
try {
// 非检查型异常:不需要强制处理
System.out.println("Value at index " + index + ": " + array[index]);
} catch (ArrayIndexOutOfBoundsException e) {
System.err.println("Error: Invalid array index " + index);
} catch (NullPointerException e) {
System.err.println("Error: Array is null");
} catch (Exception e) {
// 捕获其他可能的异常
System.err.println("An unexpected error occurred");
e.printStackTrace();
}
}
/**
* 演示自定义异常
*/
static class InsufficientFundsException extends Exception {
private double amount;
public InsufficientFundsException(String message, double amount) {
super(message);
this.amount = amount;
}
public double getAmount() {
return amount;
}
}
public static void withdraw(double balance, double amount) throws InsufficientFundsException {
if (amount > balance) {
throw new InsufficientFundsException("Insufficient funds for withdrawal", amount - balance);
}
System.out.println("Withdrawal successful: $" + amount);
}
/**
* 使用try-with-resources (Java 7+)
*/
public static void readWithResources(String filename) {
// 资源会在try块结束时自动关闭
try (FileReader fileReader = new FileReader(filename);
BufferedReader bufferedReader = new BufferedReader(fileReader)) {
String line;
while ((line = bufferedReader.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
System.err.println("Error with resources: " + e.getMessage());
}
}
public static void main(String[] args) {
System.out.println("=== Checked Exceptions Demo ===");
readFile("nonexistent.txt");
System.out.println("\n=== Unchecked Exceptions Demo ===");
int[] numbers = {1, 2, 3};
processArray(numbers, 1); // 有效索引
processArray(numbers, 5); // 无效索引
processArray(null, 0); // 空数组
System.out.println("\n=== Custom Exceptions Demo ===");
try {
withdraw(100.0, 150.0); // 余额不足
} catch (InsufficientFundsException e) {
System.err.println(e.getMessage());
System.err.println("Shortfall amount: $" + e.getAmount());
}
try {
withdraw(200.0, 150.0); // 有效取款
} catch (InsufficientFundsException e) {
System.err.println(e.getMessage());
}
System.out.println("\n=== Try-with-Resources Demo ===");
// 创建示例文件
try (FileWriter writer = new FileWriter("example.txt")) {
writer.write("Line 1\nLine 2\nLine 3");
} catch (IOException e) {
e.printStackTrace();
}
readWithResources("example.txt");
// 清理
new File("example.txt").delete();
}
}
Java 17新特性示例:
java
/**
* Java17Features.java
* 演示Java 17 (LTS版本) 的一些关键新特性
*/
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class Java17Features {
// 1. 密封类 (Sealed Classes) - 控制继承
public sealed class Shape permits Circle, Rectangle, Triangle {
public abstract double area();
}
// 子类必须是final、sealed或non-sealed
final class Circle extends Shape {
private final double radius;
public Circle(double radius) {
this.radius = radius;
}
@Override
public double area() {
return Math.PI * radius * radius;
}
@Override
public String toString() {
return "Circle[radius=" + radius + ", area=" + area() + "]";
}
}
final class Rectangle extends Shape {
private final double width;
private final double height;
public Rectangle(double width, double height) {
this.width = width;
this.height = height;
}
@Override
public double area() {
return width * height;
}
@Override
public String toString() {
return "Rectangle[width=" + width + ", height=" + height + ", area=" + area() + "]";
}
}
non-sealed class Triangle extends Shape {
private final double base;
private final double height;
public Triangle(double base, double height) {
this.base = base;
this.height = height;
}
@Override
public double area() {
return 0.5 * base * height;
}
@Override
public String toString() {
return "Triangle[base=" + base + ", height=" + height + ", area=" + area() + "]";
}
// Triangle可以被进一步继承
final class RightTriangle extends Triangle {
private final double hypotenuse;
public RightTriangle(double base, double height) {
super(base, height);
this.hypotenuse = Math.sqrt(base * base + height * height);
}
@Override
public String toString() {
return "RightTriangle[base=" + base + ", height=" + height +
", hypotenuse=" + hypotenuse + ", area=" + area() + "]";
}
}
}
// 2. 模式匹配 (Pattern Matching)
public static String describeShape(Object obj) {
// Java 17中的模式匹配简化instanceof检查
if (obj instanceof Circle c) {
return "This is a circle with radius " + c.radius;
} else if (obj instanceof Rectangle r) {
return "This is a rectangle with dimensions " + r.width + "x" + r.height;
} else if (obj instanceof Triangle t) {
return "This is a triangle with base " + t.base + " and height " + t.height;
} else {
return "Unknown shape";
}
}
// 3. 文本块 (Text Blocks) - Java 15引入,17继续支持
public static String getJsonExample() {
return """
{
"name": "John Doe",
"age": 30,
"address": {
"street": "123 Main St",
"city": "Anytown",
"country": "USA"
},
"phones": ["123-456-7890", "987-654-3210"]
}
""";
}
// 4. Records - 简化的不可变数据类
public record PersonRecord(String name, int age, String email) {
// 自动获得构造函数、getter、equals、hashCode、toString
// 可以添加额外方法
public boolean isAdult() {
return age >= 18;
}
}
public static void main(String[] args) {
System.out.println("=== Java 17 Features Demo ===\n");
// 1. 密封类示例
System.out.println("1. Sealed Classes:");
Shape[] shapes = {
new Circle(5.0),
new Rectangle(4.0, 6.0),
new Triangle(3.0, 4.0),
new Triangle.RightTriangle(3.0, 4.0) // 使用non-sealed的子类
};
for (Shape shape : shapes) {
System.out.println(shape);
}
System.out.println();
// 2. 模式匹配示例
System.out.println("2. Pattern Matching:");
for (Shape shape : shapes) {
System.out.println(describeShape(shape));
}
System.out.println();
// 3. 文本块示例
System.out.println("3. Text Blocks:");
System.out.println(getJsonExample());
System.out.println();
// 4. Records示例
System.out.println("4. Records:");
PersonRecord person1 = new PersonRecord("Alice", 25, "alice@example.com");
PersonRecord person2 = new PersonRecord("Bob", 17, "bob@example.com");
System.out.println("Person 1: " + person1);
System.out.println("Is adult? " + person1.isAdult());
System.out.println("Person 2: " + person2);
System.out.println("Is adult? " + person2.isAdult());
// Records自动实现equals
PersonRecord person3 = new PersonRecord("Alice", 25, "alice@example.com");
System.out.println("person1 equals person3? " + person1.equals(person3));
// 使用Stream API和Records
List<PersonRecord> people = List.of(person1, person2, person3);
Map<Boolean, List<PersonRecord>> adultsGrouping = people.stream()
.collect(Collectors.partitioningBy(PersonRecord::isAdult));
System.out.println("\nAdults: " + adultsGrouping.get(true));
System.out.println("Minors: " + adultsGrouping.get(false));
}
}
2. Android开发环境
2.1 Android简介
Android系统架构:
- Linux内核层: 硬件抽象、内存管理、进程管理、网络堆栈
- 硬件抽象层(HAL): 提供标准接口访问硬件功能
- Android运行时(ART): 执行DEX字节码,取代早期的Dalvik VM
- 原生C/C++库: 系统组件如SSL、SQLite、OpenGL等
- Java API框架: 提供UI、资源管理、通知等高级API
- 系统应用: 预装的核心应用(电话、联系人、浏览器等)
Android版本演进:
- Android 13 (Tiramisu, API 33): 2022年发布,增强隐私控制,通知权限
- Android 12 (Snow Cone, API 32-31): 2021年发布,Material You设计语言
- Android 11 (Red Velvet Cake, API 30): 2020年发布,对话通知,一次性权限
- Android 10 (Quince Tart, API 29): 2019年发布,系统级暗黑模式,作用域存储
Android应用组件:
- Activity: 用户界面的单个屏幕
- Service: 在后台执行长时间运行的操作
- BroadcastReceiver: 响应系统级广播事件
- ContentProvider: 管理共享应用数据
- Fragment: 可重用的UI组件,可以组合成多面板UI
- ViewModel: 以生命周期方式管理UI相关数据
- Intent: 组件间通信的消息对象
2.2 Android开发工具
核心工具:
- Android Studio: 官方IDE,基于IntelliJ IDEA
- Android SDK: 软件开发工具包,包含API库、工具、模拟器
- Android NDK: 本地开发工具包,用于C/C++开发
- Gradle: 构建系统,管理依赖、编译、打包
- ADB (Android Debug Bridge): 与设备通信的命令行工具
- Fastboot: 低级设备引导工具
- Logcat: 系统和应用日志查看器
- Profiler: 性能分析工具(CPU、内存、网络、能耗)
辅助工具:
- Layout Inspector: 检查UI布局层次
- Database Inspector: 查看和修改应用数据库
- APK Analyzer: 分析APK内容和大小
- Emulator: 虚拟设备,模拟各种Android设备
- Device File Explorer: 访问设备文件系统
- Layout Editor: 可视化设计UI布局
- Vector Asset Studio: 将SVG转换为Android矢量图形
- Profiler: 监控应用性能
2.3 安装部署Android Studio
2.3.1 系统要求检查
bash
# 1. 检查系统架构
uname -m
# 预期输出: x86_64 (Android Studio需要64位系统)
# 2. 检查RAM和交换空间
free -h
# 推荐: 8GB+ RAM,2GB+ 交换空间
# 3. 检查可用磁盘空间
df -h /home
# 推荐: 10GB+ 空闲空间 (SDK、模拟器、缓存)
# 4. 检查Java版本 (需要JDK 11或更高)
java -version
# 预期: openjdk version "11.0.18" 或更高
2.3.2 安装Android Studio
方法1: 通过snap安装 (最简单)
bash
# 1. 安装Android Studio
sudo snap install android-studio --classic
# 2. 启动Android Studio
android-studio
# 3. (可选) 创建桌面快捷方式
# 通常snap会自动创建,在应用菜单中查找"Android Studio"
方法2: 通过官方安装包安装 (推荐,更多控制)
bash
# 1. 安装依赖
sudo apt update
sudo apt install -y libc6 libncurses5 libstdc++6 lib32z1 libbz2-1.0 libgl1-mesa-glx
# 2. 下载Android Studio (最新版本)
wget https://redirector.gvt1.com/edgedl/android/studio/ide-zips/2022.3.1.16/android-studio-2022.3.1.16-linux.tar.gz
# 3. 解压到/opt目录
sudo tar -xzf android-studio-*.tar.gz -C /opt/
sudo mv /opt/android-studio-* /opt/android-studio
# 4. 创建启动脚本
sudo ln -s /opt/android-studio/bin/studio.sh /usr/local/bin/android-studio
# 5. 创建桌面快捷方式
cat > ~/.local/share/applications/android-studio.desktop <<EOF
[Desktop Entry]
Version=1.0
Type=Application
Name=Android Studio
Icon=/opt/android-studio/bin/studio.png
Exec="/opt/android-studio/bin/studio.sh" %f
Comment=Develop with pleasure!
Categories=Development;IDE;
Terminal=false
StartupWMClass=jetbrains-studio
EOF
# 6. 更新桌面数据库
update-desktop-database ~/.local/share/applications
# 7. 清理下载文件
rm android-studio-*.tar.gz
# 8. 启动Android Studio
android-studio
2.3.3 配置Android SDK
首次启动Android Studio会进行SDK配置:
-
欢迎屏幕:
- 选择"Standard"安装类型
- 选择UI主题(Dark或Light)
-
SDK组件选择:
- Android SDK Platform (最新稳定版,如Android 13/API 33)
- Android SDK Build-Tools
- Android SDK Platform-Tools
- Android SDK Tools
- Android Emulator
- Intel x86_64或ARM系统映像 (用于模拟器)
-
SDK路径配置:
- 默认位置:
~/Android/Sdk - 确保有足够磁盘空间
- 默认位置:
-
代理设置 (如果在公司网络或中国):
- 可配置HTTP代理
- 或选择离线安装包
-
验证安装:
- 在终端执行以下命令验证SDK安装
bash# 检查adb adb --version # 预期: Android Debug Bridge version 1.0.41 # 检查sdkmanager sdkmanager --list
2.3.4 配置KVM加速 (重要,用于模拟器性能)
bash
# 1. 检查CPU虚拟化支持
egrep -c '(vmx|svm)' /proc/cpuinfo
# 输出>0表示支持硬件虚拟化
# 2. 安装KVM
sudo apt update
sudo apt install -y qemu-kvm libvirt-daemon-system libvirt-clients bridge-utils virt-manager
# 3. 将当前用户添加到kvm和libvirt组
sudo usermod -aG kvm $USER
sudo usermod -aG libvirt $USER
# 4. 验证安装
systemctl is-active libvirtd
# 预期: active
# 5. 检查KVM设备权限
ls -la /dev/kvm
# 预期: crw-rw----+ 1 root kvm ...
# 6. (可选) 重启系统使组权限生效
sudo reboot
2.3.5 配置环境变量
bash
# 1. 编辑~/.bashrc或~/.zshrc
echo 'export ANDROID_HOME=$HOME/Android/Sdk' >> ~/.bashrc
echo 'export PATH=$PATH:$ANDROID_HOME/emulator' >> ~/.bashrc
echo 'export PATH=$PATH:$ANDROID_HOME/platform-tools' >> ~/.bashrc
echo 'export PATH=$PATH:$ANDROID_HOME/tools' >> ~/.bashrc
echo 'export PATH=$PATH:$ANDROID_HOME/tools/bin' >> ~/.bashrc
# 2. 使配置生效
source ~/.bashrc
# 3. 验证配置
echo $ANDROID_HOME
adb devices
emulator -list-avds
2.4 基于Android Studio开发Android应用
2.4.1 创建第一个Android应用
步骤:
- 启动Android Studio
- 点击"New Project"
- 选择"Empty Activity"模板
- 配置项目:
- Name: MyFirstApp
- Package name: com.example.myfirstapp
- Save location: 选择项目目录
- Language: Java (或Kotlin)
- Minimum API level: API 24 (Android 7.0) - 覆盖约90%设备
- 点击"Finish",等待Gradle同步完成
2.4.2 项目结构解析
MyFirstApp/
├── app/ # 应用模块
│ ├── build.gradle # 应用构建配置
│ ├── libs/ # 第三方库
│ └── src/
│ ├── androidTest/ # 仪器化测试
│ ├── main/
│ │ ├── AndroidManifest.xml # 应用配置文件
│ │ ├── java/com/example/myfirstapp/ # Java源代码
│ │ │ ├── MainActivity.java # 主Activity
│ │ │ └── MainActivity2.java
│ │ └── res/ # 资源文件
│ │ ├── drawable/ # 图像资源
│ │ ├── layout/ # UI布局
│ │ │ └── activity_main.xml
│ │ ├── mipmap/ # 应用图标
│ │ ├── values/ # 值资源
│ │ │ ├── colors.xml
│ │ │ ├── strings.xml
│ │ │ └── themes.xml
│ │ └── ...
│ └── test/ # 本地单元测试
├── gradle/ # Gradle wrapper
├── build.gradle # 项目级构建配置
├── gradle.properties # Gradle属性
├── gradlew # Gradle wrapper for Linux/Mac
├── gradlew.bat # Gradle wrapper for Windows
└── settings.gradle # 项目模块设置
2.4.3 核心组件与代码示例
示例1: 基本UI与事件处理
MainActivity.java:
java
package com.example.myfirstapp;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
// UI组件引用
private EditText editTextName;
private Button buttonSubmit;
private TextView textViewGreeting;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 初始化UI组件
initViews();
// 设置按钮点击事件
setupButtonClick();
}
/**
* 初始化UI组件
*/
private void initViews() {
editTextName = findViewById(R.id.editTextName);
buttonSubmit = findViewById(R.id.buttonSubmit);
textViewGreeting = findViewById(R.id.textViewGreeting);
}
/**
* 设置按钮点击事件处理
*/
private void setupButtonClick() {
buttonSubmit.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
handleButtonClick();
}
});
}
/**
* 处理按钮点击事件
*/
private void handleButtonClick() {
// 获取输入框内容
String name = editTextName.getText().toString().trim();
// 验证输入
if (name.isEmpty()) {
// 显示Toast提示
Toast.makeText(this, "Please enter your name", Toast.LENGTH_SHORT).show();
return;
}
// 更新文本视图
String greeting = getString(R.string.greeting_message, name);
textViewGreeting.setText(greeting);
// 清空输入框
editTextName.setText("");
// 显示成功Toast
Toast.makeText(this, "Greeting updated!", Toast.LENGTH_SHORT).show();
}
/**
* 保存实例状态
*/
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
// 保存文本视图内容
outState.putString("greeting_text", textViewGreeting.getText().toString());
}
/**
* 恢复实例状态
*/
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
// 恢复文本视图内容
String savedGreeting = savedInstanceState.getString("greeting_text", "");
if (!savedGreeting.isEmpty()) {
textViewGreeting.setText(savedGreeting);
}
}
}
activity_main.xml:
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:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp"
tools:context=".MainActivity">
<!-- 标题文本 -->
<TextView
android:id="@+id/textViewTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/app_title"
android:textSize="24sp"
android:textStyle="bold"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:layout_marginTop="32dp"/>
<!-- 名称输入提示 -->
<TextView
android:id="@+id/textViewPrompt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/name_prompt"
android:textSize="16sp"
app:layout_constraintTop_toBottomOf="@id/textViewTitle"
app:layout_constraintStart_toStartOf="parent"
android:layout_marginTop="32dp"
android:layout_marginStart="8dp"/>
<!-- 名称输入框 -->
<EditText
android:id="@+id/editTextName"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:hint="@string/name_hint"
android:inputType="textPersonName"
android:autofillHints="name"
app:layout_constraintTop_toBottomOf="@id/textViewPrompt"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:layout_marginTop="8dp"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"/>
<!-- 提交按钮 -->
<Button
android:id="@+id/buttonSubmit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/submit_button"
app:layout_constraintTop_toBottomOf="@id/editTextName"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:layout_marginTop="24dp"/>
<!-- 问候文本 -->
<TextView
android:id="@+id/textViewGreeting"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/default_greeting"
android:textSize="18sp"
android:textAlignment="center"
app:layout_constraintTop_toBottomOf="@id/buttonSubmit"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:layout_marginTop="32dp"
android:padding="16dp"
android:background="@drawable/greeting_background"/>
</androidx.constraintlayout.widget.ConstraintLayout>
strings.xml:
xml
<resources>
<string name="app_name">My First App</string>
<string name="app_title">Welcome to My App</string>
<string name="name_prompt">Enter your name:</string>
<string name="name_hint">Your name</string>
<string name="submit_button">Submit</string>
<string name="default_greeting">Hello there!</string>
<string name="greeting_message">Hello, %1$s!</string>
</resources>
greeting_background.xml (在res/drawable目录):
xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#E3F2FD" />
<corners android:radius="8dp" />
<stroke
android:width="1dp"
android:color="#90CAF9" />
</shape>
示例2: 多活动导航与隐式Intent
SecondActivity.java:
java
package com.example.myfirstapp;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
public class SecondActivity extends AppCompatActivity {
private TextView textViewMessage;
private Button buttonOpenWeb;
private Button buttonCallNumber;
private static final String PHONE_NUMBER = "1234567890";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
// 初始化UI组件
initViews();
// 设置按钮点击事件
setupButtonClicks();
// 处理传入的Intent
handleIncomingIntent();
}
/**
* 初始化UI组件
*/
private void initViews() {
textViewMessage = findViewById(R.id.textViewMessage);
buttonOpenWeb = findViewById(R.id.buttonOpenWeb);
buttonCallNumber = findViewById(R.id.buttonCallNumber);
}
/**
* 设置按钮点击事件处理
*/
private void setupButtonClicks() {
buttonOpenWeb.setOnClickListener(v -> openWebsite());
buttonCallNumber.setOnClickListener(v -> callPhoneNumber());
}
/**
* 打开网站
*/
private void openWebsite() {
try {
// 创建隐式Intent打开网页
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("https://www.android.com"));
startActivity(intent);
} catch (Exception e) {
Toast.makeText(this, "No browser app found", Toast.LENGTH_SHORT).show();
}
}
/**
* 拨打电话
*/
private void callPhoneNumber() {
try {
// 创建隐式Intent拨打电话
Intent intent = new Intent(Intent.ACTION_DIAL);
intent.setData(Uri.parse("tel:" + PHONE_NUMBER));
startActivity(intent);
} catch (Exception e) {
Toast.makeText(this, "No phone app found", Toast.LENGTH_SHORT).show();
}
}
/**
* 处理传入的Intent
*/
private void handleIncomingIntent() {
Intent intent = getIntent();
if (intent != null) {
String message = intent.getStringExtra("EXTRA_MESSAGE");
if (message != null && !message.isEmpty()) {
textViewMessage.setText(getString(R.string.received_message, message));
} else {
textViewMessage.setText(R.string.no_message_received);
}
}
}
/**
* 返回按钮处理
*/
@Override
public void onBackPressed() {
// 创建返回结果
Intent resultIntent = new Intent();
resultIntent.putExtra("RESULT_MESSAGE", "Back from Second Activity");
setResult(RESULT_OK, resultIntent);
super.onBackPressed();
}
}
activity_second.xml:
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:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp"
tools:context=".SecondActivity">
<TextView
android:id="@+id/textViewHeader"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/second_activity_title"
android:textSize="24sp"
android:textStyle="bold"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:layout_marginTop="32dp"/>
<TextView
android:id="@+id/textViewMessage"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="@string/no_message_received"
android:textSize="18sp"
android:gravity="center"
android:padding="16dp"
android:background="@drawable/message_background"
app:layout_constraintTop_toBottomOf="@id/textViewHeader"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:layout_marginTop="32dp"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"/>
<Button
android:id="@+id/buttonOpenWeb"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="@string/open_website_button"
app:layout_constraintTop_toBottomOf="@id/textViewMessage"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:layout_marginTop="48dp"
android:layout_marginStart="32dp"
android:layout_marginEnd="32dp"/>
<Button
android:id="@+id/buttonCallNumber"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="@string/call_number_button"
app:layout_constraintTop_toBottomOf="@id/buttonOpenWeb"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:layout_marginTop="16dp"
android:layout_marginStart="32dp"
android:layout_marginEnd="32dp"/>
</androidx.constraintlayout.widget.ConstraintLayout>
修改MainActivity.java添加导航:
java
// 在MainActivity类中添加以下方法
private void navigateToSecondActivity() {
// 获取输入的名称
String name = editTextName.getText().toString().trim();
if (name.isEmpty()) {
Toast.makeText(this, "Please enter your name first", Toast.LENGTH_SHORT).show();
return;
}
// 创建显式Intent
Intent intent = new Intent(this, SecondActivity.class);
// 传递数据
intent.putExtra("EXTRA_MESSAGE", name);
// 启动活动并等待结果
startActivityForResult(intent, 1);
}
// 在setupButtonClick方法中添加第二个按钮
private Button buttonSecondActivity;
private void initViews() {
// ... 原有代码
buttonSecondActivity = findViewById(R.id.buttonSecondActivity);
}
private void setupButtonClick() {
buttonSubmit.setOnClickListener(...); // 原有代码
// 添加第二个按钮点击处理
buttonSecondActivity.setOnClickListener(v -> navigateToSecondActivity());
}
// 处理返回结果
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == 1 && resultCode == RESULT_OK && data != null) {
String resultMessage = data.getStringExtra("RESULT_MESSAGE");
if (resultMessage != null) {
Toast.makeText(this, "Result: " + resultMessage, Toast.LENGTH_LONG).show();
}
}
}
添加按钮到activity_main.xml:
xml
<!-- 在按钮Submit下方添加 -->
<Button
android:id="@+id/buttonSecondActivity"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Go to Second Activity"
app:layout_constraintTop_toBottomOf="@id/buttonSubmit"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:layout_marginTop="16dp"/>
示例3: RecyclerView实现列表
创建用户模型类User.java:
java
package com.example.myfirstapp.model;
public class User {
private String name;
private String email;
private int age;
public User(String name, String email, int age) {
this.name = name;
this.email = email;
this.age = age;
}
public String getName() {
return name;
}
public String getEmail() {
return email;
}
public int getAge() {
return age;
}
}
创建适配器UserAdapter.java:
java
package com.example.myfirstapp.adapter;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.example.myfirstapp.R;
import com.example.myfirstapp.model.User;
import java.util.List;
public class UserAdapter extends RecyclerView.Adapter<UserAdapter.UserViewHolder> {
private List<User> userList;
private OnUserClickListener listener;
// 点击事件接口
public interface OnUserClickListener {
void onUserClick(User user);
}
public UserAdapter(List<User> userList, OnUserClickListener listener) {
this.userList = userList;
this.listener = listener;
}
@NonNull
@Override
public UserViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_user, parent, false);
return new UserViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull UserViewHolder holder, int position) {
User user = userList.get(position);
holder.bind(user);
// 设置点击事件
holder.itemView.setOnClickListener(v -> {
if (listener != null) {
listener.onUserClick(user);
}
});
}
@Override
public int getItemCount() {
return userList.size();
}
// ViewHolder类
public static class UserViewHolder extends RecyclerView.ViewHolder {
private TextView textViewName;
private TextView textViewEmail;
private TextView textViewAge;
public UserViewHolder(@NonNull View itemView) {
super(itemView);
textViewName = itemView.findViewById(R.id.textViewName);
textViewEmail = itemView.findViewById(R.id.textViewEmail);
textViewAge = itemView.findViewById(R.id.textViewAge);
}
public void bind(User user) {
textViewName.setText(user.getName());
textViewEmail.setText(user.getEmail());
textViewAge.setText(String.valueOf(user.getAge()));
}
}
}
创建列表项布局item_user.xml (在res/layout目录):
xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView
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="wrap_content"
android:layout_margin="8dp"
app:cardCornerRadius="8dp"
app:cardElevation="2dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="16dp">
<TextView
android:id="@+id/textViewName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="18sp"
android:textStyle="bold"/>
<TextView
android:id="@+id/textViewEmail"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="14sp"
android:textColor="#666666"/>
<TextView
android:id="@+id/textViewAge"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="14sp"
android:layout_marginTop="4dp"/>
</LinearLayout>
</androidx.cardview.widget.CardView>
创建UserListActivity.java:
java
package com.example.myfirstapp;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.os.Bundle;
import android.widget.Toast;
import com.example.myfirstapp.adapter.UserAdapter;
import com.example.myfirstapp.model.User;
import java.util.ArrayList;
import java.util.List;
public class UserListActivity extends AppCompatActivity {
private RecyclerView recyclerViewUsers;
private UserAdapter userAdapter;
private List<User> userList = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_user_list);
// 初始化视图
initViews();
// 准备数据
prepareUserData();
// 设置RecyclerView
setupRecyclerView();
}
private void initViews() {
recyclerViewUsers = findViewById(R.id.recyclerViewUsers);
}
private void prepareUserData() {
// 模拟用户数据
userList.add(new User("Alice Johnson", "alice@example.com", 28));
userList.add(new User("Bob Smith", "bob.smith@example.com", 35));
userList.add(new User("Charlie Brown", "charlie@example.com", 42));
userList.add(new User("Diana Prince", "diana.p@example.com", 31));
userList.add(new User("Edward Norton", "edward.n@example.com", 29));
userList.add(new User("Fiona Gallagher", "fiona@example.com", 33));
userList.add(new User("George Wilson", "george.w@example.com", 45));
userList.add(new User("Hannah Baker", "hannah.b@example.com", 27));
}
private void setupRecyclerView() {
// 设置布局管理器
recyclerViewUsers.setLayoutManager(new LinearLayoutManager(this));
// 创建并设置适配器
userAdapter = new UserAdapter(userList, user -> {
// 处理用户点击
showUserDetails(user);
});
recyclerViewUsers.setAdapter(userAdapter);
}
private void showUserDetails(User user) {
Toast.makeText(this,
"User Details:\nName: " + user.getName() +
"\nEmail: " + user.getEmail() +
"\nAge: " + user.getAge(),
Toast.LENGTH_SHORT).show();
}
}
创建activity_user_list.xml:
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:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".UserListActivity">
<TextView
android:id="@+id/textViewTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/user_list_title"
android:textSize="24sp"
android:textStyle="bold"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:layout_marginTop="16dp"/>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerViewUsers"
android:layout_width="0dp"
android:layout_height="0dp"
android:padding="8dp"
app:layout_constraintTop_toBottomOf="@id/textViewTitle"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:scrollbars="vertical"/>
</androidx.constraintlayout.widget.ConstraintLayout>
在strings.xml中添加:
xml
<string name="user_list_title">User List</string>
在AndroidManifest.xml中注册新Activity:
xml
<activity
android:name=".UserListActivity"
android:label="User List"
android:parentActivityName=".MainActivity">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".MainActivity" />
</activity>
2.4.4 调试与部署
调试技巧:
-
Logcat:
javaimport android.util.Log; // 在代码中添加日志 Log.d("MainActivity", "Button clicked"); Log.i("MainActivity", "User data loaded"); Log.e("MainActivity", "Error loading data", exception); -
断点调试:
- 在代码行号左侧单击添加断点
- 点击Debug按钮启动调试
- 使用调试工具栏控制执行流程
- 查看变量值、调用栈、线程状态
-
布局检查:
- 使用Layout Inspector检查UI层次
- 使用Layout Validation查看不同屏幕尺寸的预览
- 使用Pixel Perfect工具精确检查UI元素位置
部署到设备:
-
物理设备:
- 启用开发者选项 (设置 > 关于手机 > 连续点击版本号7次)
- 在开发者选项中启用USB调试
- 通过USB连接设备
- 在Android Studio中选择设备并点击Run
-
模拟器:
- 在AVD Manager中创建虚拟设备
- 选择设备定义、系统映像、配置
- 启动模拟器
- 在Android Studio中选择模拟器并点击Run
发布准备:
gradle
// app/build.gradle
android {
...
buildTypes {
release {
minifyEnabled true
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.release
}
}
signingConfigs {
release {
storeFile file("my-release-key.jks")
storePassword "password"
keyAlias "my-key-alias"
keyPassword "password"
}
}
}
3. 本章小结
3.1 重点回顾
-
Java开发环境:
- OpenJDK是Ubuntu上的推荐选择
- 使用update-alternatives管理多版本JDK
- IntelliJ IDEA提供强大的Java开发体验
- Java 17引入了密封类、模式匹配等现代特性
-
Android开发环境:
- Android Studio是官方IDE,提供完整工具链
- SDK Manager管理Android平台和工具版本
- 模拟器需要KVM加速获得良好性能
- Gradle是Android的构建系统
-
Android应用开发:
- Activity是应用的基本构建块
- UI通过XML布局文件定义,Java/Kotlin提供逻辑
- Intent实现组件间通信
- RecyclerView高效显示大型数据集
- 生命周期管理是Android开发核心概念
3.2 最佳实践
-
Java开发最佳实践:
- 使用try-with-resources自动管理资源
- 采用记录类(Records)简化数据类
- 使用密封类(Sealed Classes)控制继承层次
- 优先使用不可变对象
- 遵循命名和代码风格规范
-
Android开发最佳实践:
- 将字符串、尺寸等资源外部化
- 为不同屏幕尺寸提供替代资源
- 使用ViewModel管理UI相关数据
- 避免在主线程执行耗时操作
- 使用约束布局(ConstraintLayout)创建灵活UI
- 实现适当的状态保存和恢复
-
性能优化:
- 减小APK大小 (资源压缩、代码混淆)
- 优化内存使用 (避免内存泄漏)
- 最小化主线程工作
- 使用适当的图片格式和尺寸
- 实现分页加载大型数据集
3.3 学习资源推荐
-
Java学习资源:
- Oracle Java文档
- Java教程
- 《Effective Java》by Joshua Bloch
- 《Java并发编程实战》
-
Android学习资源:
- Android开发者网站
- Android Codelabs
- 《第一行代码:Android》
- 《Android编程权威指南》
-
工具和社区:
- Stack Overflow
- GitHub开源项目
- Android Dev Summit视频
- JetBrains官方博客
通过本章学习,您已掌握在Ubuntu 22.04环境下配置Java和Android开发环境的完整流程,以及开发基础应用程序的技能。持续实践这些知识,并探索更高级的主题,将帮助您成长为一名熟练的Java/Android开发者。