演示代码示例
本页面汇集了教程中的所有演示代码,按模块组织,方便查阅和复制。
📁 代码结构
code-examples/
├── 02-java-basics/ # Java 基础示例
│ ├── OopExample.java # 面向对象:继承、接口、抽象类
│ ├── CollectionsExample.java # 集合:List、Map、Set、泛型
│ └── DesignPatterns.java # 设计模式:单例、观察者、构建者、适配器
├── 04-activity-fragment/ # Activity 与 Fragment
│ ├── LifecycleActivity.java # Activity 生命周期演示
│ └── DetailActivity.java # 页面间数据传递
├── 05-ui-layouts/ # UI 布局
│ └── profile_layout.xml # ConstraintLayout 用户资料页布局
├── 06-recyclerview/ # 列表展示
│ └── UserListAdapter.java # ListAdapter + DiffUtil 示例
├── 07-networking-persistence/ # 网络与存储
│ └── ApiExample.java # Retrofit 完整使用示例
├── 08-architecture/ # 架构模式
│ └── MVVMExample.java # MVVM 架构完整示例
└── 10-legacy-migration/ # 老项目迁移
└── BeforeMigration.java # Java → Kotlin 对比示例🚀 如何使用
- 点击对应模块查看代码
- 复制代码到你的 Android Studio 项目中
- 根据注释理解代码逻辑
- 动手修改和实验
📝 代码约定
- 所有示例基于 JDK 17 和 compileSdk 34
- 使用 AndroidX 库而非 Support Library
- 遵循现代 Android 开发最佳实践
- 包含详细的中英文注释
📖 代码预览
快速跳转
| 基础入门 | 核心开发 | 进阶技能 | 实战指南 |
|---|---|---|---|
| OOP 面向对象 | Activity 生命周期 | Retrofit 网络请求 | Java → Kotlin 迁移 |
| 集合框架 | 页面间数据传递 | MVVM 架构 | |
| 设计模式 | ConstraintLayout 布局 | ||
| RecyclerView 列表 |
Java 基础:面向对象
java
package com.example.basics;
import java.util.ArrayList;
import java.util.List;
/**
* 面向对象示例:对比前端原型链和 Java 类继承
*
* 前端类比:
* - class = ES6 class
* - extends = extends
* - interface = TypeScript interface
* - abstract class = 无直接对应,类似抽象基类
*/
public class OopExample {
// ==================== 基础类定义 ====================
/**
* 基类:动物
* 前端类比:class Animal { constructor(name) { this.name = name; } }
*/
static class Animal {
private String name;
private int age;
// 构造方法(前端类比:constructor)
public Animal(String name, int age) {
this.name = name;
this.age = age;
}
// Getter/Setter(前端类比:get name() / set name())
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public int getAge() { return age; }
public void setAge(int age) { this.age = age; }
// 可重写的方法
public String makeSound() {
return "...";
}
@Override
public String toString() {
return name + " (" + age + "岁)";
}
}
/**
* 继承:狗
* 前端类比:class Dog extends Animal { makeSound() { return '汪!'; } }
*/
static class Dog extends Animal {
private String breed;
public Dog(String name, int age, String breed) {
super(name, age); // 调用父类构造方法(前端:super(name, age))
this.breed = breed;
}
@Override
public String makeSound() {
return "汪汪!";
}
public String getBreed() { return breed; }
}
/**
* 继承:猫
*/
static class Cat extends Animal {
private boolean isIndoor;
public Cat(String name, int age, boolean isIndoor) {
super(name, age);
this.isIndoor = isIndoor;
}
@Override
public String makeSound() {
return "喵喵~";
}
public boolean isIndoor() { return isIndoor; }
}
// ==================== 接口示例 ====================
/**
* 接口:可训练的
* 前端类比:interface Trainable { train(command: string): void; }
*/
interface Trainable {
void train(String command);
boolean canPerform(String trick);
}
/**
* 接口:可抚摸的
*/
interface Pettable {
void pet();
String getReaction();
}
/**
* 多接口实现:导盲犬
* 前端类比:class GuideDog extends Dog implements Trainable, Pettable
*/
static class GuideDog extends Dog implements Trainable, Pettable {
private List<String> knownTricks = new ArrayList<>();
public GuideDog(String name, int age, String breed) {
super(name, age, breed);
}
@Override
public void train(String command) {
knownTricks.add(command);
System.out.println(getName() + " 学会了: " + command);
}
@Override
public boolean canPerform(String trick) {
return knownTricks.contains(trick);
}
@Override
public void pet() {
System.out.println(getName() + " 摇尾巴");
}
@Override
public String getReaction() {
return "友好地蹭你的手";
}
}
// ==================== 抽象类示例 ====================
/**
* 抽象类:形状
* 前端类比:abstract class Shape { abstract area(): number; }
*/
static abstract class Shape {
protected String color;
public Shape(String color) {
this.color = color;
}
// 抽象方法(必须在子类中实现)
public abstract double area();
public abstract double perimeter();
// 具体方法
public void describe() {
System.out.println(color + " 形状,面积: " + area() + ",周长: " + perimeter());
}
}
static class Circle extends Shape {
private double radius;
public Circle(String color, double radius) {
super(color);
this.radius = radius;
}
@Override
public double area() {
return Math.PI * radius * radius;
}
@Override
public double perimeter() {
return 2 * Math.PI * radius;
}
}
static class Rectangle extends Shape {
private double width, height;
public Rectangle(String color, double width, double height) {
super(color);
this.width = width;
this.height = height;
}
@Override
public double area() {
return width * height;
}
@Override
public double perimeter() {
return 2 * (width + height);
}
}
// ==================== 演示入口 ====================
public static void main(String[] args) {
System.out.println("=== 继承与多态 ===");
Animal dog = new Dog("旺财", 3, "金毛");
Animal cat = new Cat("咪咪", 2, true);
System.out.println(dog); // 旺财 (3岁)
System.out.println(cat); // 咪咪 (2岁)
System.out.println(dog.makeSound()); // 汪汪!
System.out.println(cat.makeSound()); // 喵喵~
System.out.println("\n=== 接口实现 ===");
GuideDog guideDog = new GuideDog("Lucky", 4, "拉布拉多");
guideDog.train("带路");
guideDog.train("停下");
guideDog.pet();
System.out.println("会带路吗?" + guideDog.canPerform("带路")); // true
System.out.println("会翻滚吗?" + guideDog.canPerform("翻滚")); // false
System.out.println("\n=== 抽象类 ===");
Shape circle = new Circle("红色", 5);
Shape rect = new Rectangle("蓝色", 4, 6);
circle.describe();
rect.describe();
System.out.println("\n=== 类型检查(前端:instanceof) ===");
System.out.println("dog instanceof Animal: " + (dog instanceof Animal)); // true
System.out.println("dog instanceof Dog: " + (dog instanceof Dog)); // true
System.out.println("dog instanceof Cat: " + (dog instanceof Cat)); // false
System.out.println("guideDog instanceof Trainable: " + (guideDog instanceof Trainable)); // true
}
}集合框架
java
package com.example.basics;
import java.util.*;
import java.util.stream.Collectors;
/**
* 集合框架示例:对比前端数组/对象操作
*
* 前端类比:
* - List<T> = Array<T>
* - Map<K,V> = Map<K,V> / Record<K,V>
* - Set<T> = Set<T>
* - Iterator = for...of
*/
public class CollectionsExample {
// ==================== List 示例 ====================
/**
* List 操作对比
*
* | Java | JavaScript |
* |------|-----------|
* | list.add(item) | arr.push(item) |
* | list.get(i) | arr[i] |
* | list.remove(i) | arr.splice(i, 1) |
* | list.size() | arr.length |
* | list.contains(x) | arr.includes(x) |
*/
static void listExamples() {
System.out.println("=== List 示例 ===");
// ArrayList(最常用,类似 JS 数组)
List<String> fruits = new ArrayList<>();
fruits.add("苹果");
fruits.add("香蕉");
fruits.add("橙子");
System.out.println("水果列表: " + fruits);
System.out.println("第一个: " + fruits.get(0)); // 苹果
System.out.println("包含香蕉? " + fruits.contains("香蕉")); // true
// 遍历(前端:fruits.forEach(f => ...))
System.out.println("\n遍历:");
for (String fruit : fruits) {
System.out.println(" - " + fruit);
}
// Lambda 遍历(前端:fruits.forEach(f => console.log(f)))
System.out.println("\nLambda 遍历:");
fruits.forEach(fruit -> System.out.println(" * " + fruit));
// Stream API(前端:arr.filter/map/reduce)
List<String> longNames = fruits.stream()
.filter(f -> f.length() >= 2)
.collect(Collectors.toList());
System.out.println("名字>=2字符: " + longNames);
// 映射(前端:arr.map)
List<Integer> lengths = fruits.stream()
.map(String::length)
.collect(Collectors.toList());
System.out.println("名字长度: " + lengths);
// 排序(前端:arr.sort)
fruits.sort(Comparator.naturalOrder());
System.out.println("排序后: " + fruits);
}
// ==================== Map 示例 ====================
/**
* Map 操作对比
*
* | Java | JavaScript |
* |------|-----------|
* | map.put(k, v) | map.set(k, v) / obj[k] = v |
* | map.get(k) | map.get(k) / obj[k] |
* | map.containsKey(k) | map.has(k) / k in obj |
* | map.keySet() | map.keys() / Object.keys(obj) |
*/
static void mapExamples() {
System.out.println("\n=== Map 示例 ===");
// HashMap(无序,类似 JS Map 或对象)
Map<String, Integer> scores = new HashMap<>();
scores.put("张三", 95);
scores.put("李四", 87);
scores.put("王五", 92);
System.out.println("成绩表: " + scores);
System.out.println("张三成绩: " + scores.get("张三")); // 95
System.out.println("包含李四? " + scores.containsKey("李四")); // true
// 遍历(前端:for (const [k, v] of map))
System.out.println("\n遍历:");
for (Map.Entry<String, Integer> entry : scores.entrySet()) {
System.out.println(" " + entry.getKey() + ": " + entry.getValue());
}
// Lambda 遍历
System.out.println("\nLambda 遍历:");
scores.forEach((name, score) ->
System.out.println(" " + name + " -> " + score)
);
// getOrDefault(前端:obj[k] ?? defaultValue)
System.out.println("赵六成绩: " + scores.getOrDefault("赵六", 0)); // 0
// TreeMap(有序 Map)
Map<String, Integer> sortedScores = new TreeMap<>(scores);
System.out.println("按姓名排序: " + sortedScores);
}
// ==================== Set 示例 ====================
/**
* Set 操作对比
*
* | Java | JavaScript |
* |------|-----------|
* | set.add(x) | set.add(x) |
* | set.contains(x) | set.has(x) |
* | set.remove(x) | set.delete(x) |
* | set.size() | set.size |
*/
static void setExamples() {
System.out.println("\n=== Set 示例 ===");
Set<String> tags = new HashSet<>();
tags.add("Android");
tags.add("Java");
tags.add("Kotlin");
tags.add("Android"); // 重复,不会添加
System.out.println("标签集合: " + tags);
System.out.println("包含 Java? " + tags.contains("Java")); // true
System.out.println("集合大小: " + tags.size()); // 3
// 集合运算
Set<String> myTags = new HashSet<>(Arrays.asList("Java", "Web", "Android"));
Set<String> yourTags = new HashSet<>(Arrays.asList("Kotlin", "Android", "iOS"));
// 交集(前端:new Set([...a].filter(x => b.has(x))))
Set<String> intersection = new HashSet<>(myTags);
intersection.retainAll(yourTags);
System.out.println("交集: " + intersection); // [Android]
// 并集(前端:new Set([...a, ...b]))
Set<String> union = new HashSet<>(myTags);
union.addAll(yourTags);
System.out.println("并集: " + union); // [Java, Web, Android, Kotlin, iOS]
// 差集
Set<String> difference = new HashSet<>(myTags);
difference.removeAll(yourTags);
System.out.println("差集 (my - your): " + difference); // [Java, Web]
}
// ==================== 泛型示例 ====================
/**
* 泛型类(前端类比:class Stack<T>)
*/
static class Stack<T> {
private List<T> items = new ArrayList<>();
public void push(T item) {
items.add(item);
}
public T pop() {
if (items.isEmpty()) throw new RuntimeException("栈为空");
return items.remove(items.size() - 1);
}
public T peek() {
if (items.isEmpty()) throw new RuntimeException("栈为空");
return items.get(items.size() - 1);
}
public boolean isEmpty() {
return items.isEmpty();
}
public int size() {
return items.size();
}
}
/**
* 泛型方法
*/
static <T extends Comparable<T>> T findMax(List<T> list) {
if (list.isEmpty()) throw new IllegalArgumentException("列表为空");
T max = list.get(0);
for (T item : list) {
if (item.compareTo(max) > 0) {
max = item;
}
}
return max;
}
static void genericsExamples() {
System.out.println("\n=== 泛型示例 ===");
// 泛型类
Stack<String> stack = new Stack<>();
stack.push("A");
stack.push("B");
stack.push("C");
System.out.println("栈顶: " + stack.peek()); // C
System.out.println("弹出: " + stack.pop()); // C
System.out.println("栈顶: " + stack.peek()); // B
// 泛型方法
List<Integer> numbers = Arrays.asList(3, 7, 1, 9, 4);
System.out.println("最大值: " + findMax(numbers)); // 9
List<String> words = Arrays.asList("banana", "apple", "cherry");
System.out.println("最大字符串: " + findMax(words)); // cherry
}
// ==================== 主方法 ====================
public static void main(String[] args) {
listExamples();
mapExamples();
setExamples();
genericsExamples();
}
}设计模式
java
package com.example.basics;
/**
* 设计模式示例:Android 开发中常用的模式
*
* 包含:
* - 单例模式 (Singleton)
* - 观察者模式 (Observer)
* - 构建者模式 (Builder)
* - 适配器模式 (Adapter)
*/
public class DesignPatterns {
// ==================== 单例模式 ====================
/**
* 单例模式:确保一个类只有一个实例
*
* 前端类比:Redux Store、全局状态管理
* Android 场景:数据库实例、网络客户端、配置管理
*/
static class DatabaseHelper {
// 静态实例(前端:module 级别的变量)
private static DatabaseHelper instance;
private String connectionString;
private boolean isConnected;
// 私有构造方法(前端:私有 constructor 或工厂函数)
private DatabaseHelper() {
this.connectionString = "jdbc:sqlite:app.db";
this.isConnected = false;
}
// 获取实例(线程安全)
public static synchronized DatabaseHelper getInstance() {
if (instance == null) {
instance = new DatabaseHelper();
}
return instance;
}
public void connect() {
isConnected = true;
System.out.println("数据库已连接: " + connectionString);
}
public void disconnect() {
isConnected = false;
System.out.println("数据库已断开");
}
public boolean isConnected() {
return isConnected;
}
}
// ==================== 观察者模式 ====================
/**
* 观察者接口(前端:EventListener / Subscriber)
*/
interface Observer<T> {
void update(T data);
}
/**
* 被观察者(前端:EventEmitter / Subject)
* Android 场景:LiveData、EventBus
*/
static class LiveData<T> {
private T value;
private List<Observer<T>> observers = new java.util.ArrayList<>();
public void observe(Observer<T> observer) {
observers.add(observer);
}
public void removeObserver(Observer<T> observer) {
observers.remove(observer);
}
public void setValue(T newValue) {
this.value = newValue;
notifyObservers();
}
public T getValue() {
return value;
}
private void notifyObservers() {
for (Observer<T> observer : observers) {
observer.update(value);
}
}
}
/**
* 用户状态示例
*/
static class UserState {
public String name;
public boolean isLoggedIn;
public UserState(String name, boolean isLoggedIn) {
this.name = name;
this.isLoggedIn = isLoggedIn;
}
@Override
public String toString() {
return name + (isLoggedIn ? " (在线)" : " (离线)");
}
}
// ==================== 构建者模式 ====================
/**
* 构建者模式:复杂对象的分步构建
*
* 前端类比:链式调用、配置对象构建
* Android 场景:Dialog、Request、Notification
*/
static class HttpRequest {
private final String url;
private final String method;
private final Map<String, String> headers;
private final String body;
private final int timeout;
// 私有构造方法,只能通过 Builder 创建
private HttpRequest(Builder builder) {
this.url = builder.url;
this.method = builder.method;
this.headers = builder.headers;
this.body = builder.body;
this.timeout = builder.timeout;
}
@Override
public String toString() {
return method + " " + url + "\n" +
"Headers: " + headers + "\n" +
"Body: " + (body != null ? body : "(无)") + "\n" +
"Timeout: " + timeout + "ms";
}
/**
* Builder 类(前端:链式调用 new Request().url().method().build())
*/
public static class Builder {
private String url;
private String method = "GET";
private Map<String, String> headers = new java.util.HashMap<>();
private String body;
private int timeout = 30000;
public Builder(String url) {
this.url = url;
}
public Builder method(String method) {
this.method = method;
return this; // 返回 this 实现链式调用
}
public Builder header(String key, String value) {
this.headers.put(key, value);
return this;
}
public Builder body(String body) {
this.body = body;
return this;
}
public Builder timeout(int timeout) {
this.timeout = timeout;
return this;
}
public HttpRequest build() {
return new HttpRequest(this);
}
}
}
// ==================== 适配器模式 ====================
/**
* 适配器模式:接口转换
*
* 前端类比:数据转换层、API 适配
* Android 场景:RecyclerView.Adapter
*/
// 旧接口
interface OldDataSource {
String[] getRawData();
}
// 新接口
interface NewDataSource {
List<User> getUsers();
}
static class User {
public String name;
public int age;
public User(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return name + " (" + age + ")";
}
}
// 旧实现
static class LegacyDataSource implements OldDataSource {
@Override
public String[] getRawData() {
return new String[]{"张三|25", "李四|30", "王五|28"};
}
}
// 适配器:将旧接口转换为新接口
static class DataSourceAdapter implements NewDataSource {
private OldDataSource oldSource;
public DataSourceAdapter(OldDataSource oldSource) {
this.oldSource = oldSource;
}
@Override
public List<User> getUsers() {
List<User> users = new java.util.ArrayList<>();
String[] rawData = oldSource.getRawData();
for (String item : rawData) {
String[] parts = item.split("\\|");
users.add(new User(parts[0], Integer.parseInt(parts[1])));
}
return users;
}
}
// ==================== 演示入口 ====================
public static void main(String[] args) {
System.out.println("=== 单例模式 ===");
DatabaseHelper db1 = DatabaseHelper.getInstance();
DatabaseHelper db2 = DatabaseHelper.getInstance();
System.out.println("db1 == db2: " + (db1 == db2)); // true
db1.connect();
System.out.println("db2 连接状态: " + db2.isConnected()); // true
System.out.println("\n=== 观察者模式 ===");
LiveData<UserState> userState = new LiveData<>();
userState.observe(state -> System.out.println("UI 更新: " + state));
userState.observe(state -> System.out.println("日志记录: " + state));
userState.setValue(new UserState("张三", true));
userState.setValue(new UserState("张三", false));
System.out.println("\n=== 构建者模式 ===");
HttpRequest request = new HttpRequest.Builder("https://api.example.com/users")
.method("POST")
.header("Content-Type", "application/json")
.header("Authorization", "Bearer token123")
.body("{\"name\": \"张三\", \"age\": 25}")
.timeout(10000)
.build();
System.out.println(request);
System.out.println("\n=== 适配器模式 ===");
OldDataSource oldSource = new LegacyDataSource();
NewDataSource adapter = new DataSourceAdapter(oldSource);
System.out.println("原始数据: " + java.util.Arrays.toString(oldSource.getRawData()));
System.out.println("适配后: " + adapter.getUsers());
}
}Activity 生命周期
java
package com.example.activity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.widget.Button;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
/**
* Activity 生命周期演示
*
* 前端类比:
* - onCreate() = 页面初始化(DOMContentLoaded)
* - onStart() = 页面可见
* - onResume() = 页面获得焦点
* - onPause() = 页面失去焦点
* - onStop() = 页面不可见
* - onDestroy() = 页面销毁(beforeunload)
*
* 运行此 Activity 并在 Logcat 中观察生命周期日志输出。
*/
public class LifecycleActivity extends AppCompatActivity {
private static final String TAG = "LifecycleActivity";
private TextView lifecycleText;
private int resumeCount = 0;
/**
* Activity 被创建时调用
* 前端类比:componentDidMount / onMounted
*/
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(TAG, "onCreate: Activity 被创建");
// 设置布局(前端类比:innerHTML = template)
// 这里用代码创建 UI,实际项目中应该用 XML 布局
lifecycleText = new TextView(this);
lifecycleText.setTextSize(20);
lifecycleText.setPadding(32, 32, 32, 32);
Button navigateButton = new Button(this);
navigateButton.setText("打开 DetailActivity");
navigateButton.setOnClickListener(v -> {
// 显式 Intent(前端类比:router.push('/detail'))
Intent intent = new Intent(this, DetailActivity.class);
intent.putExtra("title", "从 LifecycleActivity 传递的标题");
intent.putExtra("id", 42);
startActivity(intent);
});
Button backButton = new Button(this);
backButton.setText("返回");
backButton.setOnClickListener(v -> finish()); // 关闭当前 Activity
android.widget.LinearLayout layout = new android.widget.LinearLayout(this);
layout.setOrientation(android.widget.LinearLayout.VERTICAL);
layout.addView(lifecycleText);
layout.addView(navigateButton);
layout.addView(backButton);
setContentView(layout);
// 恢复状态(前端类比:从 sessionStorage 恢复)
if (savedInstanceState != null) {
resumeCount = savedInstanceState.getInt("resumeCount", 0);
Log.d(TAG, "onCreate: 从 savedInstanceState 恢复状态");
}
lifecycleText.setText("LifecycleActivity\nonCreate 调用\nResume 次数: " + resumeCount);
}
/**
* Activity 变为可见时调用
*/
@Override
protected void onStart() {
super.onStart();
Log.d(TAG, "onStart: Activity 变为可见");
}
/**
* Activity 获得焦点,进入前台时调用
* 前端类比:window focus 事件
*/
@Override
protected void onResume() {
super.onResume();
resumeCount++;
Log.d(TAG, "onResume: Activity 进入前台 (第 " + resumeCount + " 次)");
lifecycleText.setText("LifecycleActivity\nonResume 调用\nResume 次数: " + resumeCount);
}
/**
* Activity 失去焦点时调用
* 前端类比:window blur 事件
*/
@Override
protected void onPause() {
super.onPause();
Log.d(TAG, "onPause: Activity 失去焦点");
}
/**
* Activity 变为不可见时调用
*/
@Override
protected void onStop() {
super.onStop();
Log.d(TAG, "onStop: Activity 变为不可见");
}
/**
* Activity 被销毁时调用
* 前端类比:componentWillUnmount / onUnmounted
*/
@Override
protected void onDestroy() {
super.onDestroy();
Log.d(TAG, "onDestroy: Activity 被销毁");
}
/**
* 保存状态(系统可能杀死进程时)
* 前端类比:beforeunload 时保存到 sessionStorage
*/
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt("resumeCount", resumeCount);
Log.d(TAG, "onSaveInstanceState: 保存 resumeCount = " + resumeCount);
}
/**
* 从后台返回前台时调用(在 onStart 之前)
*/
@Override
protected void onRestart() {
super.onRestart();
Log.d(TAG, "onRestart: Activity 从后台返回");
}
}页面间数据传递
java
package com.example.activity;
import android.content.Intent;
import android.os.Bundle;
import android.widget.Button;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
/**
* DetailActivity:演示页面间数据传递
*
* 前端类比:
* - Intent extras = route params / query params
* - setResult() + finish() = emit event + go back
* - startActivityForResult() = 弹窗回调
*/
public class DetailActivity extends AppCompatActivity {
private static final String TAG = "DetailActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 接收 Intent 数据(前端类比:this.$route.params)
Intent intent = getIntent();
String title = intent.getStringExtra("title");
int id = intent.getIntExtra("id", -1);
android.util.Log.d(TAG, "接收到数据: title=" + title + ", id=" + id);
// 创建 UI
TextView titleView = new TextView(this);
titleView.setTextSize(24);
titleView.setPadding(32, 32, 32, 32);
titleView.setText("详情页面\n\n标题: " + title + "\nID: " + id);
Button backButton = new Button(this);
backButton.setText("返回");
backButton.setOnClickListener(v -> {
// 返回结果给调用方(前端类比:emit('close', result))
Intent result = new Intent();
result.putExtra("result", "操作完成");
setResult(RESULT_OK, result);
finish(); // 关闭当前 Activity
});
Button shareButton = new Button(this);
shareButton.setText("分享(隐式 Intent)");
shareButton.setOnClickListener(v -> {
// 隐式 Intent(前端类比:window.open 或调用系统分享)
Intent shareIntent = new Intent(Intent.ACTION_SEND);
shareIntent.setType("text/plain");
shareIntent.putExtra(Intent.EXTRA_TEXT, "查看: " + title);
startActivity(Intent.createChooser(shareIntent, "分享到"));
});
android.widget.LinearLayout layout = new android.widget.LinearLayout(this);
layout.setOrientation(android.widget.LinearLayout.VERTICAL);
layout.addView(titleView);
layout.addView(backButton);
layout.addView(shareButton);
setContentView(layout);
}
}UI 布局:ConstraintLayout
xml
<?xml version="1.0" encoding="utf-8"?>
<!--
ConstraintLayout 示例:现代 Android 布局
前端类比:
- ConstraintLayout = CSS Flexbox + Grid
- layout_constraintX_toXOf = flex/grid 对齐
- layout_margin = margin
- layout_padding = padding
依赖:implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
-->
<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">
<!-- 头像(圆形) -->
<ImageView
android:id="@+id/avatar"
android:layout_width="80dp"
android:layout_height="80dp"
android:src="@drawable/ic_person"
android:background="@drawable/circle_background"
android:scaleType="centerCrop"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
tools:ignore="ContentDescription" />
<!-- 用户名 -->
<TextView
android:id="@+id/username"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="张三"
android:textSize="24sp"
android:textStyle="bold"
android:textColor="#333333"
android:layout_marginStart="16dp"
app:layout_constraintTop_toTopOf="@id/avatar"
app:layout_constraintStart_toEndOf="@id/avatar"
app:layout_constraintEnd_toEndOf="parent"
tools:text="用户名" />
<!-- 邮箱 -->
<TextView
android:id="@+id/email"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="zhangsan@example.com"
android:textSize="14sp"
android:textColor="#666666"
android:layout_marginTop="4dp"
app:layout_constraintTop_toBottomOf="@id/username"
app:layout_constraintStart_toStartOf="@id/username"
app:layout_constraintEnd_toEndOf="@id/username"
tools:text="email@example.com" />
<!-- 分隔线 -->
<View
android:id="@+id/divider"
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#E0E0E0"
android:layout_marginTop="16dp"
app:layout_constraintTop_toBottomOf="@id/avatar" />
<!-- 统计信息区域 -->
<LinearLayout
android:id="@+id/stats_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginTop="16dp"
app:layout_constraintTop_toBottomOf="@id/divider">
<!-- 粉丝数 -->
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical"
android:gravity="center">
<TextView
android:id="@+id/followers_count"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="1.2K"
android:textSize="20sp"
android:textStyle="bold"
android:textColor="#333333" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="粉丝"
android:textSize="12sp"
android:textColor="#999999" />
</LinearLayout>
<!-- 关注数 -->
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical"
android:gravity="center">
<TextView
android:id="@+id/following_count"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="256"
android:textSize="20sp"
android:textStyle="bold"
android:textColor="#333333" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="关注"
android:textSize="12sp"
android:textColor="#999999" />
</LinearLayout>
<!-- 获赞数 -->
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical"
android:gravity="center">
<TextView
android:id="@+id/likes_count"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="5.8K"
android:textSize="20sp"
android:textStyle="bold"
android:textColor="#333333" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="获赞"
android:textSize="12sp"
android:textColor="#999999" />
</LinearLayout>
</LinearLayout>
<!-- 关注按钮 -->
<Button
android:id="@+id/follow_button"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="关注"
android:textSize="16sp"
android:layout_marginTop="24dp"
app:layout_constraintTop_toBottomOf="@id/stats_container"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toStartOf="@id/message_button"
android:layout_marginEnd="8dp" />
<!-- 私信按钮 -->
<Button
android:id="@+id/message_button"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="私信"
android:textSize="16sp"
android:backgroundTint="#E0E0E0"
android:textColor="#333333"
app:layout_constraintTop_toTopOf="@id/follow_button"
app:layout_constraintStart_toEndOf="@id/follow_button"
app:layout_constraintEnd_toEndOf="parent"
android:layout_marginStart="8dp" />
<!-- 个人简介 -->
<TextView
android:id="@+id/bio_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="个人简介"
android:textSize="16sp"
android:textStyle="bold"
android:textColor="#333333"
android:layout_marginTop="24dp"
app:layout_constraintTop_toBottomOf="@id/follow_button"
app:layout_constraintStart_toStartOf="parent" />
<TextView
android:id="@+id/bio_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Android 开发者,热爱开源,专注于移动端架构设计。"
android:textSize="14sp"
android:textColor="#666666"
android:lineSpacingExtra="4dp"
android:layout_marginTop="8dp"
app:layout_constraintTop_toBottomOf="@id/bio_label" />
</androidx.constraintlayout.widget.ConstraintLayout>RecyclerView:ListAdapter + DiffUtil
java
package com.example.recyclerview;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.DiffUtil;
import androidx.recyclerview.widget.ListAdapter;
import androidx.recyclerview.widget.RecyclerView;
/**
* RecyclerView Adapter 示例:使用 ListAdapter + DiffUtil
*
* 前端类比:
* - Adapter = Vue 的 v-for / React 的 .map()
* - ViewHolder = 列表项组件
* - DiffUtil = Vue 的 key 属性 / React 的 key prop
*
* ListAdapter 比传统 RecyclerView.Adapter 更高效:
* - 自动计算差异(DiffUtil)
* - 只更新变化的项
* - 动画效果更流畅
*/
public class UserListAdapter extends ListAdapter<User, UserListAdapter.UserViewHolder> {
private OnItemClickListener listener;
/**
* 点击事件接口(前端类比:@click / onClick)
*/
public interface OnItemClickListener {
void onItemClick(User user, int position);
void onItemLongClick(User user, int position);
}
public UserListAdapter(OnItemClickListener listener) {
super(DIFF_CALLBACK);
this.listener = listener;
}
/**
* DiffUtil 回调:告诉 RecyclerView 如何比较两个 item
*
* 前端类比:Vue 的 :key="user.id" 或 React 的 key={user.id}
*/
private static final DiffUtil.ItemCallback<User> DIFF_CALLBACK =
new DiffUtil.ItemCallback<User>() {
/**
* 判断两个 item 是否是同一个(前端类比:id 是否相同)
*/
@Override
public boolean areItemsTheSame(@NonNull User oldItem, @NonNull User newItem) {
return oldItem.getId() == newItem.getId();
}
/**
* 判断两个 item 内容是否相同(前端类比:deepEqual)
*/
@Override
public boolean areContentsTheSame(@NonNull User oldItem, @NonNull User newItem) {
return oldItem.getName().equals(newItem.getName()) &&
oldItem.getEmail().equals(newItem.getEmail()) &&
oldItem.getRole().equals(newItem.getRole());
}
};
/**
* 创建 ViewHolder(前端类比:创建组件实例)
*
* 只在需要新 ViewHolder 时调用,不会为每个 item 都调用。
* RecyclerView 会复用滑出屏幕的 ViewHolder。
*/
@NonNull
@Override
public UserViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
// 加载布局(前端类比:读取 template)
View view = LayoutInflater.from(parent.getContext())
.inflate(android.R.layout.simple_list_item_2, parent, false);
return new UserViewHolder(view);
}
/**
* 绑定数据到 ViewHolder(前端类比:给组件传 props)
*
* 每次 item 显示时都会调用。
*/
@Override
public void onBindViewHolder(@NonNull UserViewHolder holder, int position) {
User user = getItem(position); // ListAdapter 提供的便捷方法
holder.bind(user, position, listener);
}
/**
* ViewHolder:持有列表项的视图引用
*
* 前端类比:列表项组件的实例
* 作用:避免重复调用 findViewById(性能优化)
*/
static class UserViewHolder extends RecyclerView.ViewHolder {
private TextView text1;
private TextView text2;
public UserViewHolder(@NonNull View itemView) {
super(itemView);
// simple_list_item_2 包含两个 TextView
text1 = itemView.findViewById(android.R.id.text1);
text2 = itemView.findViewById(android.R.id.text2);
}
public void bind(User user, int position, OnItemClickListener listener) {
text1.setText(user.getName() + " (" + user.getRole() + ")");
text2.setText(user.getEmail());
// 点击事件(前端类比:@click)
itemView.setOnClickListener(v -> {
if (listener != null) {
listener.onItemClick(user, position);
}
});
// 长按事件(前端类比:@contextmenu)
itemView.setOnLongClickListener(v -> {
if (listener != null) {
listener.onItemLongClick(user, position);
}
return true;
});
}
}
/**
* 用户数据类
*/
public static class User {
private int id;
private String name;
private String email;
private String role;
public User(int id, String name, String email, String role) {
this.id = id;
this.name = name;
this.email = email;
this.role = role;
}
public int getId() { return id; }
public String getName() { return name; }
public String getEmail() { return email; }
public String getRole() { return role; }
}
}网络请求:Retrofit
java
package com.example.networking;
import java.io.IOException;
import java.util.List;
import okhttp3.OkHttpClient;
import okhttp3.logging.HttpLoggingInterceptor;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
import retrofit2.http.Body;
import retrofit2.http.GET;
import retrofit2.http.POST;
import retrofit2.http.Path;
import retrofit2.http.Query;
/**
* Retrofit 网络请求示例
*
* 前端类比:
* - Retrofit = axios / fetch
* - @GET/@POST = method: 'GET'/'POST'
* - @Path = 路径参数 (如 /users/:id)
* - @Query = 查询参数 (?page=1)
* - @Body = 请求体
* - Call<T> = Promise<T>
*
* 依赖配置 (build.gradle):
* implementation 'com.squareup.retrofit2:retrofit:2.9.0'
* implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
* implementation 'com.squareup.okhttp3:logging-interceptor:4.12.0'
*/
public class ApiExample {
// ==================== 数据模型 ====================
/**
* 用户数据类(Gson 自动解析 JSON)
*/
public static class User {
private int id;
private String name;
private String email;
private String phone;
public User(int id, String name, String email, String phone) {
this.id = id;
this.name = name;
this.email = email;
this.phone = phone;
}
@Override
public String toString() {
return "User{id=" + id + ", name='" + name + "', email='" + email + "'}";
}
}
/**
* 创建用户请求体
*/
public static class CreateUserRequest {
private String name;
private String email;
private String phone;
public CreateUserRequest(String name, String email, String phone) {
this.name = name;
this.email = email;
this.phone = phone;
}
}
/**
* 分页响应
*/
public static class PaginatedResponse<T> {
private List<T> data;
private int page;
private int perPage;
private int total;
public List<T> getData() { return data; }
public int getPage() { return page; }
public int getTotal() { return total; }
}
// ==================== API 接口定义 ====================
/**
* API 接口(前端类比:axios 实例的 methods)
*
* Retrofit 通过注解自动将接口方法转换为 HTTP 请求。
*/
public interface ApiService {
/**
* GET /users
* 前端类比:axios.get('/users')
*/
@GET("users")
Call<List<User>> getUsers();
/**
* GET /users?page=1&perPage=10
* 前端类比:axios.get('/users', { params: { page, perPage } })
*/
@GET("users")
Call<PaginatedResponse<User>> getUsers(
@Query("page") int page,
@Query("perPage") int perPage
);
/**
* GET /users/123
* 前端类比:axios.get(`/users/${id}`)
*/
@GET("users/{id}")
Call<User> getUser(@Path("id") int userId);
/**
* POST /users
* 前端类比:axios.post('/users', userData)
*/
@POST("users")
Call<User> createUser(@Body CreateUserRequest user);
}
// ==================== Retrofit 客户端 ====================
/**
* 创建 Retrofit 实例(前端类比:axios.create())
*/
public static Retrofit createRetrofit() {
// 日志拦截器(前端类比:axios 的 request/response 拦截器)
HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor(System.out::println);
loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
// OkHttpClient(底层 HTTP 客户端)
OkHttpClient client = new OkHttpClient.Builder()
.addInterceptor(loggingInterceptor)
.addInterceptor(chain -> {
// 自定义拦截器:添加认证头
okhttp3.Request request = chain.request().newBuilder()
.addHeader("Authorization", "Bearer your-token-here")
.addHeader("Content-Type", "application/json")
.build();
return chain.proceed(request);
})
.build();
// Retrofit 实例
return new Retrofit.Builder()
.baseUrl("https://api.example.com/") // 基础 URL
.client(client)
.addConverterFactory(GsonConverterFactory.create()) // JSON 解析
.build();
}
// ==================== 使用示例 ====================
/**
* 异步请求示例(前端类比:async/await 或 .then())
*/
public static void fetchUsers(ApiService api) {
System.out.println("=== 获取用户列表 ===");
Call<List<User>> call = api.getUsers();
// 异步执行(前端类比:axios.get('/users').then(...))
call.enqueue(new Callback<List<User>>() {
@Override
public void onResponse(Call<List<User>> call, Response<List<User>> response) {
if (response.isSuccessful()) {
List<User> users = response.body();
System.out.println("成功! 用户数量: " + users.size());
users.forEach(System.out::println);
} else {
System.out.println("失败: " + response.code());
}
}
@Override
public void onFailure(Call<List<User>> call, Throwable t) {
System.out.println("网络错误: " + t.getMessage());
}
});
}
/**
* 同步请求示例(前端类比:await axios.get())
* 注意:不能在 Android 主线程调用!
*/
public static User fetchUserSync(ApiService api, int userId) throws IOException {
System.out.println("=== 获取单个用户 (同步) ===");
Call<User> call = api.getUser(userId);
Response<User> response = call.execute(); // 阻塞调用
if (response.isSuccessful()) {
User user = response.body();
System.out.println("用户: " + user);
return user;
} else {
throw new IOException("HTTP " + response.code());
}
}
/**
* 分页请求示例
*/
public static void fetchUsersPaginated(ApiService api, int page) {
System.out.println("=== 分页请求 (第 " + page + " 页) ===");
Call<PaginatedResponse<User>> call = api.getUsers(page, 10);
call.enqueue(new Callback<PaginatedResponse<User>>() {
@Override
public void onResponse(Call<PaginatedResponse<User>> call,
Response<PaginatedResponse<User>> response) {
if (response.isSuccessful()) {
PaginatedResponse<User> result = response.body();
System.out.println("第 " + result.getPage() + " 页,共 " + result.getTotal() + " 条");
result.getData().forEach(System.out::println);
}
}
@Override
public void onFailure(Call<PaginatedResponse<User>> call, Throwable t) {
System.out.println("错误: " + t.getMessage());
}
});
}
/**
* POST 请求示例
*/
public static void createUser(ApiService api) {
System.out.println("=== 创建用户 ===");
CreateUserRequest request = new CreateUserRequest(
"张三", "zhangsan@example.com", "13800138000"
);
Call<User> call = api.createUser(request);
call.enqueue(new Callback<User>() {
@Override
public void onResponse(Call<User> call, Response<User> response) {
if (response.isSuccessful()) {
User created = response.body();
System.out.println("创建成功: " + created);
} else {
System.out.println("创建失败: " + response.code());
}
}
@Override
public void onFailure(Call<User> call, Throwable t) {
System.out.println("网络错误: " + t.getMessage());
}
});
}
// ==================== 演示入口 ====================
public static void main(String[] args) {
// 创建 API 服务
Retrofit retrofit = createRetrofit();
ApiService api = retrofit.create(ApiService.class);
// 演示各种请求
fetchUsers(api);
fetchUsersPaginated(api, 1);
createUser(api);
// 同步请求(需要在子线程中)
new Thread(() -> {
try {
fetchUserSync(api, 1);
} catch (IOException e) {
e.printStackTrace();
}
}).start();
// 保持主线程运行(仅用于演示)
try { Thread.sleep(5000); } catch (InterruptedException ignored) {}
}
}架构模式:MVVM
java
package com.example.architecture;
/**
* MVVM 架构模式示例
*
* MVVM (Model-View-ViewModel) 是 Android 官方推荐的架构模式。
*
* 前端类比:
* - ViewModel = Vue 的 reactive state / React 的 useState
* - LiveData = Vue 的 ref / React 的状态更新触发重渲染
* - Repository = Vuex/Pinia 的 actions
*
* 依赖配置 (build.gradle):
* implementation 'androidx.lifecycle:lifecycle-viewmodel:2.7.0'
* implementation 'androidx.lifecycle:lifecycle-livedata:2.7.0'
*/
public class MVVMExample {
// ==================== Model 层 ====================
/**
* 用户数据模型
*/
public static class User {
private int id;
private String name;
private String email;
public User(int id, String name, String email) {
this.id = id;
this.name = name;
this.email = email;
}
public int getId() { return id; }
public String getName() { return name; }
public String getEmail() { return email; }
@Override
public String toString() {
return name + " (" + email + ")";
}
}
// ==================== Repository 层 ====================
/**
* Repository:数据源抽象(前端类比:Vuex actions / API service)
*
* 职责:
* - 决定从哪个数据源获取数据(网络/本地缓存)
* - 处理数据转换
* - 对 ViewModel 隐藏数据源细节
*/
public static class UserRepository {
// 模拟网络请求
public User getUser(int userId) {
// 实际项目中:调用 Retrofit API
System.out.println("Repository: 从网络获取用户 " + userId);
return new User(userId, "张三", "zhangsan@example.com");
}
// 模拟更新用户
public boolean updateUser(User user) {
System.out.println("Repository: 更新用户 " + user.getName());
return true;
}
}
// ==================== ViewModel 层 ====================
/**
* 简化的 LiveData(前端类比:Vue ref / React useState)
*
* 实际 Android 中使用:androidx.lifecycle.LiveData
*/
public static class LiveData<T> {
private T value;
private java.util.List<java.util.function.Consumer<T>> observers = new java.util.ArrayList<>();
public void observe(java.util.function.Consumer<T> observer) {
observers.add(observer);
if (value != null) {
observer.accept(value);
}
}
public void setValue(T newValue) {
this.value = newValue;
observers.forEach(observer -> observer.accept(newValue));
}
public T getValue() {
return value;
}
}
/**
* ViewModel:管理 UI 数据(前端类比:Vue setup() / React 组件状态)
*
* 特点:
* - 生命周期感知:Activity 旋转重建时数据保留
* - 不持有 View 引用:避免内存泄漏
* - 职责:准备 UI 数据、处理用户交互
*/
public static class UserViewModel {
private final UserRepository repository;
// UI 状态(前端类比:const user = ref(null))
private final LiveData<User> user = new LiveData<>();
private final LiveData<Boolean> isLoading = new LiveData<>();
private final LiveData<String> errorMessage = new LiveData<>();
public UserViewModel() {
this.repository = new UserRepository();
}
// 暴露 LiveData 给 View 观察
public LiveData<User> getUser() { return user; }
public LiveData<Boolean> getIsLoading() { return isLoading; }
public LiveData<String> getErrorMessage() { return errorMessage; }
/**
* 加载用户(前端类比:const loadUser = async (id) => {...})
*/
public void loadUser(int userId) {
isLoading.setValue(true);
errorMessage.setValue(null);
// 模拟异步请求(实际项目中用协程或线程池)
new Thread(() -> {
try {
Thread.sleep(500); // 模拟网络延迟
User loadedUser = repository.getUser(userId);
user.setValue(loadedUser);
isLoading.setValue(false);
} catch (Exception e) {
errorMessage.setValue("加载失败: " + e.getMessage());
isLoading.setValue(false);
}
}).start();
}
/**
* 更新用户
*/
public void updateUser(String newName) {
User currentUser = user.getValue();
if (currentUser == null) return;
isLoading.setValue(true);
new Thread(() -> {
User updatedUser = new User(
currentUser.getId(),
newName,
currentUser.getEmail()
);
boolean success = repository.updateUser(updatedUser);
if (success) {
user.setValue(updatedUser);
} else {
errorMessage.setValue("更新失败");
}
isLoading.setValue(false);
}).start();
}
}
// ==================== View 层 ====================
/**
* 模拟 Activity/Fragment(View 层)
*
* 职责:
* - 显示 UI
* - 观察 ViewModel 数据变化
* - 转发用户操作给 ViewModel
*/
public static class UserView {
private final UserViewModel viewModel;
public UserView() {
viewModel = new UserViewModel();
setupObservers();
}
/**
* 设置数据观察者(前端类比:watch / useEffect)
*/
private void setupObservers() {
// 观察用户数据变化
viewModel.getUser().observe(user -> {
System.out.println("View: 显示用户 " + user);
// 实际项目中:textView.setText(user.getName())
});
// 观察加载状态
viewModel.getIsLoading().observe(isLoading -> {
if (isLoading) {
System.out.println("View: 显示加载动画");
} else {
System.out.println("View: 隐藏加载动画");
}
});
// 观察错误信息
viewModel.getErrorMessage().observe(error -> {
if (error != null) {
System.out.println("View: 显示错误 " + error);
}
});
}
/**
* 模拟用户点击加载按钮
*/
public void onLoadUserClick(int userId) {
System.out.println("View: 用户点击加载按钮");
viewModel.loadUser(userId);
}
/**
* 模拟用户点击更新按钮
*/
public void onUpdateUserClick(String newName) {
System.out.println("View: 用户点击更新按钮,新名字: " + newName);
viewModel.updateUser(newName);
}
}
// ==================== 演示入口 ====================
public static void main(String[] args) throws InterruptedException {
System.out.println("=== MVVM 架构演示 ===\n");
UserView view = new UserView();
// 模拟用户操作
view.onLoadUserClick(1);
Thread.sleep(1000); // 等待加载完成
System.out.println();
view.onUpdateUserClick("李四");
Thread.sleep(1000); // 等待更新完成
System.out.println("\n=== MVVM 数据流 ===");
System.out.println("User 点击 → View 调用 ViewModel → ViewModel 调用 Repository");
System.out.println("Repository 返回数据 → ViewModel 更新 LiveData → View 自动刷新");
}
}Java → Kotlin 迁移对比
java
package com.example.migration;
/**
* 老项目迁移示例:Java → Kotlin 对比
*
* 展示同一段代码在 Java 和 Kotlin 中的写法差异,
* 帮助前端开发者理解 Kotlin 的语法特点。
*/
public class BeforeMigration {
// ==================== 数据类 ====================
/**
* Java 数据类:需要手写 getter/setter/toString/equals/hashCode
*/
public static class User {
private int id;
private String name;
private String email;
private boolean isActive;
public User(int id, String name, String email, boolean isActive) {
this.id = id;
this.name = name;
this.email = email;
this.isActive = isActive;
}
public int getId() { return id; }
public void setId(int id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getEmail() { return email; }
public void setEmail(String email) { this.email = email; }
public boolean isActive() { return isActive; }
public void setActive(boolean active) { isActive = active; }
@Override
public String toString() {
return "User{id=" + id + ", name='" + name + "', email='" + email + "', isActive=" + isActive + "}";
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
User user = (User) obj;
return id == user.id;
}
@Override
public int hashCode() {
return id;
}
}
// ==================== 单例 ====================
/**
* Java 单例:需要手写同步和实例管理
*/
public static class AppConfig {
private static AppConfig instance;
private String apiUrl;
private int timeout;
private AppConfig() {
this.apiUrl = "https://api.example.com";
this.timeout = 30000;
}
public static synchronized AppConfig getInstance() {
if (instance == null) {
instance = new AppConfig();
}
return instance;
}
public String getApiUrl() { return apiUrl; }
public int getTimeout() { return timeout; }
}
// ==================== 扩展函数(Java 需要工具类) ====================
/**
* Java 工具类:字符串操作
* Kotlin 中可以直接定义为扩展函数
*/
public static class StringUtils {
public static String capitalize(String str) {
if (str == null || str.isEmpty()) return str;
return str.substring(0, 1).toUpperCase() + str.substring(1);
}
public static boolean isValidEmail(String email) {
return email != null && email.contains("@") && email.contains(".");
}
public static String truncate(String str, int maxLength) {
if (str == null || str.length() <= maxLength) return str;
return str.substring(0, maxLength) + "...";
}
}
// ==================== 回调接口 ====================
/**
* Java 回调接口(Kotlin 可以用高阶函数替代)
*/
public interface Callback<T> {
void onSuccess(T result);
void onError(String error);
}
/**
* 使用回调的异步操作
*/
public static void fetchData(int id, Callback<String> callback) {
new Thread(() -> {
try {
Thread.sleep(100);
callback.onSuccess("数据 " + id);
} catch (InterruptedException e) {
callback.onError("中断: " + e.getMessage());
}
}).start();
}
// ==================== 演示 ====================
public static void main(String[] args) {
System.out.println("=== Java 版本 ===\n");
// 数据类
User user = new User(1, "张三", "zhangsan@example.com", true);
System.out.println(user);
// 单例
AppConfig config = AppConfig.getInstance();
System.out.println("API URL: " + config.getApiUrl());
// 工具类
System.out.println("capitalize: " + StringUtils.capitalize("hello"));
System.out.println("isValidEmail: " + StringUtils.isValidEmail("a@b.c"));
// 回调
fetchData(42, new Callback<String>() {
@Override
public void onSuccess(String result) {
System.out.println("成功: " + result);
}
@Override
public void onError(String error) {
System.out.println("错误: " + error);
}
});
}
}
/**
* Kotlin 版本(仅供参考,实际应在 .kt 文件中)
*
* ```kotlin
* // 数据类:自动生成 getter/setter/toString/equals/hashCode
* data class User(
* val id: Int,
* var name: String,
* var email: String,
* var isActive: Boolean = true
* )
*
* // 单例:object 关键字
* object AppConfig {
* val apiUrl = "https://api.example.com"
* val timeout = 30000
* }
*
* // 扩展函数
* fun String.capitalize(): String =
* this.replaceFirstChar { it.uppercase() }
*
* fun String.isValidEmail(): Boolean =
* this.contains("@") && this.contains(".")
*
* fun String.truncate(maxLength: Int): String =
* if (length <= maxLength) this else "${take(maxLength)}..."
*
* // 高阶函数(替代回调接口)
* fun fetchData(
* id: Int,
* onSuccess: (String) -> Unit,
* onError: (String) -> Unit
* ) {
* thread {
* try {
* Thread.sleep(100)
* onSuccess("数据 $id")
* } catch (e: InterruptedException) {
* onError("中断: ${e.message}")
* }
* }
* }
*
* // 使用
* fun main() {
* val user = User(1, "张三", "zhangsan@example.com")
* println(user)
*
* println(AppConfig.apiUrl)
*
* println("hello".capitalize())
* println("a@b.c".isValidEmail())
*
* fetchData(
* id = 42,
* onSuccess = { result -> println("成功: $result") },
* onError = { error -> println("错误: $error") }
* )
* }
* ```
*/