Skip to content

演示代码示例

本页面汇集了教程中的所有演示代码,按模块组织,方便查阅和复制。

📁 代码结构

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 对比示例

🚀 如何使用

  1. 点击对应模块查看代码
  2. 复制代码到你的 Android Studio 项目中
  3. 根据注释理解代码逻辑
  4. 动手修改和实验

📝 代码约定

  • 所有示例基于 JDK 17compileSdk 34
  • 使用 AndroidX 库而非 Support Library
  • 遵循现代 Android 开发最佳实践
  • 包含详细的中英文注释

📖 代码预览

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") }
 *     )
 * }
 * ```
 */

面向前端开发者的 Java Android 开发教程