# MVVM架构

## 目录
- [MVVM模式介绍](#mvvm模式介绍)
- [DataBinding](#databinding)
- [ViewModel](#viewmodel)
- [LiveData](#livedata)
- [MVVM实现示例](#mvvm实现示例)
- [MVVM优缺点](#mvvm优缺点)
- [MVVM最佳实践](#mvvm最佳实践)
- [面试常见问题](#面试常见问题)

---

## MVVM模式介绍

### MVVM 概念

MVVM（Model-View-ViewModel）是一种软件架构模式：

- **Model**：数据和业务逻辑
- **View**：用户界面（XML 布局）
- **ViewModel**：连接 View 和 Model，处理 UI 逻辑

### MVVM 架构图

```
┌─────────┐
│  View   │  ←─── 显示数据（通过 DataBinding）
└────┬────┘
     │ 数据绑定
     ↓
┌─────────┐
│ViewModel │  ←─── 处理 UI 逻辑，持有 LiveData
└────┬────┘
     │ 更新
     ↓
┌─────────┐
│  Model  │  ←─── 数据和业务逻辑
└─────────┘
```

### MVVM 数据流

1. **用户操作 View** → View 通过 DataBinding 或事件绑定调用 ViewModel
2. **ViewModel 处理** → 调用 Model 获取数据
3. **Model 返回数据** → ViewModel 更新 LiveData
4. **LiveData 通知 View** → View 自动更新（通过 DataBinding 或 Observer）

### MVVM 核心特点

1. **数据双向绑定**：View 和 ViewModel 自动同步
2. **View 被动更新**：通过观察者模式自动更新
3. **ViewModel 无 View 引用**：不持有 View 引用，避免内存泄漏
4. **生命周期感知**：LiveData 自动处理生命周期

---

## DataBinding

### DataBinding 简介

DataBinding 是 Android 官方提供的数据绑定框架，可以在 XML 布局中直接绑定数据。

### 启用 DataBinding

```gradle
android {
    dataBinding {
        enabled = true
    }
}
```

### DataBinding 使用

```xml
<!-- activity_main.xml -->
<layout xmlns:android="http://schemas.android.com/apk/res/android">
    <data>
        <variable
            name="user"
            type="com.example.User" />
        <variable
            name="viewModel"
            type="com.example.UserViewModel" />
    </data>
    
    <LinearLayout>
        <TextView
            android:text="@{user.name}" />
        <TextView
            android:text="@{user.email}" />
        <Button
            android:onClick="@{() -> viewModel.onButtonClick()}"
            android:text="Click" />
    </LinearLayout>
</layout>
```

```java
// Activity
public class MainActivity extends AppCompatActivity {
    private ActivityMainBinding binding;
    private UserViewModel viewModel;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
        viewModel = ViewModelProviders.of(this).get(UserViewModel.class);
        binding.setViewModel(viewModel);
        binding.setLifecycleOwner(this);
    }
}
```

### DataBinding 表达式

```xml
<!-- 基本表达式 -->
<TextView android:text="@{user.name}" />
<TextView android:text="@{String.valueOf(user.age)}" />

<!-- 空值合并 -->
<TextView android:text="@{user.name ?? `Default Name`}" />

<!-- 条件表达式 -->
<TextView
    android:text="@{user.isVip ? `VIP` : `Normal`}"
    android:visibility="@{user.isVip ? View.VISIBLE : View.GONE}" />

<!-- 集合访问 -->
<TextView android:text="@{users[0].name}" />

<!-- 方法调用 -->
<Button android:onClick="@{() -> viewModel.onClick()}" />
<Button android:onClick="@{viewModel::onClick}" />

<!-- 资源引用 -->
<TextView android:text="@{@string/name_format(user.name)}" />
```

---

## ViewModel

### ViewModel 简介

ViewModel 是 Android Jetpack 组件，用于存储和管理 UI 相关的数据，在配置变更（如屏幕旋转）时保持数据。

### ViewModel 特点

1. **生命周期感知**：与 Activity/Fragment 生命周期关联
2. **配置变更保持**：屏幕旋转等配置变更时数据不丢失
3. **无 View 引用**：不持有 View 引用，避免内存泄漏
4. **数据共享**：可以在 Fragment 之间共享数据

### ViewModel 使用

```java
// ViewModel
public class UserViewModel extends ViewModel {
    private MutableLiveData<List<User>> users = new MutableLiveData<>();
    private UserRepository repository;
    
    public UserViewModel() {
        repository = new UserRepository();
        loadUsers();
    }
    
    public LiveData<List<User>> getUsers() {
        return users;
    }
    
    public void loadUsers() {
        repository.getUsers(new UserRepository.Callback<List<User>>() {
            @Override
            public void onSuccess(List<User> data) {
                users.setValue(data);
            }
            
            @Override
            public void onError(String error) {
                // 处理错误
            }
        });
    }
    
    public void addUser(String name, String email) {
        User user = new User(UUID.randomUUID().toString(), name, email);
        repository.addUser(user, new UserRepository.Callback<Void>() {
            @Override
            public void onSuccess(Void data) {
                loadUsers();
            }
            
            @Override
            public void onError(String error) {
                // 处理错误
            }
        });
    }
    
    @Override
    protected void onCleared() {
        super.onCleared();
        // 清理资源
    }
}

// Activity
public class UserActivity extends AppCompatActivity {
    private UserViewModel viewModel;
    private ActivityUserBinding binding;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        binding = DataBindingUtil.setContentView(this, R.layout.activity_user);
        
        viewModel = ViewModelProviders.of(this).get(UserViewModel.class);
        binding.setViewModel(viewModel);
        binding.setLifecycleOwner(this);
        
        observeViewModel();
    }
    
    private void observeViewModel() {
        viewModel.getUsers().observe(this, users -> {
            // 更新 UI
            adapter.updateUsers(users);
        });
    }
}
```

### ViewModel 工厂

```java
// ViewModelFactory
public class UserViewModelFactory extends ViewModelProvider.Factory {
    private UserRepository repository;
    
    public UserViewModelFactory(UserRepository repository) {
        this.repository = repository;
    }
    
    @Override
    public <T extends ViewModel> T create(Class<T> modelClass) {
        if (modelClass.isAssignableFrom(UserViewModel.class)) {
            return (T) new UserViewModel(repository);
        }
        throw new IllegalArgumentException("Unknown ViewModel class");
    }
}

// 使用
UserRepository repository = new UserRepository();
UserViewModelFactory factory = new UserViewModelFactory(repository);
viewModel = ViewModelProviders.of(this, factory).get(UserViewModel.class);
```

---

## LiveData

### LiveData 简介

LiveData 是 Android Jetpack 组件，是一个可观察的数据持有者，具有生命周期感知能力。

### LiveData 特点

1. **生命周期感知**：自动管理观察者的生命周期
2. **自动更新**：数据变化时自动通知观察者
3. **避免内存泄漏**：观察者自动取消订阅
4. **配置变更保持**：配置变更时数据不丢失

### LiveData 使用

```java
// ViewModel
public class UserViewModel extends ViewModel {
    private MutableLiveData<List<User>> users = new MutableLiveData<>();
    private MutableLiveData<String> error = new MutableLiveData<>();
    private MutableLiveData<Boolean> loading = new MutableLiveData<>();
    
    public LiveData<List<User>> getUsers() {
        return users;
    }
    
    public LiveData<String> getError() {
        return error;
    }
    
    public LiveData<Boolean> getLoading() {
        return loading;
    }
    
    public void loadUsers() {
        loading.setValue(true);
        repository.getUsers(new UserRepository.Callback<List<User>>() {
            @Override
            public void onSuccess(List<User> data) {
                loading.setValue(false);
                users.setValue(data);
            }
            
            @Override
            public void onError(String errorMsg) {
                loading.setValue(false);
                error.setValue(errorMsg);
            }
        });
    }
}

// Activity
public class UserActivity extends AppCompatActivity {
    private UserViewModel viewModel;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_user);
        
        viewModel = ViewModelProviders.of(this).get(UserViewModel.class);
        observeViewModel();
    }
    
    private void observeViewModel() {
        // 观察用户列表
        viewModel.getUsers().observe(this, users -> {
            adapter.updateUsers(users);
        });
        
        // 观察错误信息
        viewModel.getError().observe(this, error -> {
            Toast.makeText(this, error, Toast.LENGTH_SHORT).show();
        });
        
        // 观察加载状态
        viewModel.getLoading().observe(this, isLoading -> {
            if (isLoading) {
                progressBar.setVisibility(View.VISIBLE);
            } else {
                progressBar.setVisibility(View.GONE);
            }
        });
    }
}
```

### LiveData 转换

```java
// Transformations.map：转换数据
LiveData<String> userName = Transformations.map(users, users -> {
    return users.get(0).getName();
});

// Transformations.switchMap：切换 LiveData
LiveData<List<User>> filteredUsers = Transformations.switchMap(searchQuery, query -> {
    return repository.searchUsers(query);
});

// 自定义转换
public class UserNameTransformations {
    public static LiveData<String> getUserName(LiveData<List<User>> users) {
        return Transformations.map(users, userList -> {
            if (userList != null && !userList.isEmpty()) {
                return userList.get(0).getName();
            }
            return "";
        });
    }
}
```

### MediatorLiveData

```java
// 合并多个 LiveData
public class UserViewModel extends ViewModel {
    private MediatorLiveData<List<User>> users = new MediatorLiveData<>();
    private LiveData<List<User>> localUsers;
    private LiveData<List<User>> remoteUsers;
    
    public UserViewModel() {
        localUsers = repository.getLocalUsers();
        remoteUsers = repository.getRemoteUsers();
        
        users.addSource(localUsers, users::setValue);
        users.addSource(remoteUsers, users::setValue);
    }
    
    public LiveData<List<User>> getUsers() {
        return users;
    }
}
```

---

## MVVM实现示例

### 完整示例：用户列表

```java
// Model：用户数据模型
public class User {
    private String id;
    private String name;
    private String email;
    
    public User(String id, String name, String email) {
        this.id = id;
        this.name = name;
        this.email = email;
    }
    
    // Getters and Setters
    public String getId() { return id; }
    public String getName() { return name; }
    public String getEmail() { return email; }
}

// Model：用户业务逻辑
public class UserRepository {
    private List<User> users = new ArrayList<>();
    
    public void addUser(User user, Callback callback) {
        new Thread(() -> {
            try {
                Thread.sleep(1000);
                users.add(user);
                callback.onSuccess();
            } catch (InterruptedException e) {
                callback.onError(e.getMessage());
            }
        }).start();
    }
    
    public void getUsers(Callback<List<User>> callback) {
        new Thread(() -> {
            try {
                Thread.sleep(500);
                callback.onSuccess(new ArrayList<>(users));
            } catch (InterruptedException e) {
                callback.onError(e.getMessage());
            }
        }).start();
    }
    
    interface Callback<T> {
        void onSuccess(T data);
        void onError(String error);
    }
}

// ViewModel
public class UserViewModel extends ViewModel {
    private MutableLiveData<List<User>> users = new MutableLiveData<>();
    private MutableLiveData<String> error = new MutableLiveData<>();
    private MutableLiveData<Boolean> loading = new MutableLiveData<>();
    private UserRepository repository;
    
    public UserViewModel() {
        repository = new UserRepository();
        loadUsers();
    }
    
    public LiveData<List<User>> getUsers() {
        return users;
    }
    
    public LiveData<String> getError() {
        return error;
    }
    
    public LiveData<Boolean> getLoading() {
        return loading;
    }
    
    public void loadUsers() {
        loading.setValue(true);
        repository.getUsers(new UserRepository.Callback<List<User>>() {
            @Override
            public void onSuccess(List<User> data) {
                loading.setValue(false);
                users.setValue(data);
            }
            
            @Override
            public void onError(String errorMsg) {
                loading.setValue(false);
                error.setValue(errorMsg);
            }
        });
    }
    
    public void addUser(String name, String email) {
        if (name.isEmpty() || email.isEmpty()) {
            error.setValue("Name and Email cannot be empty");
            return;
        }
        
        loading.setValue(true);
        User user = new User(UUID.randomUUID().toString(), name, email);
        repository.addUser(user, new UserRepository.Callback<Void>() {
            @Override
            public void onSuccess(Void data) {
                loading.setValue(false);
                loadUsers();
            }
            
            @Override
            public void onError(String errorMsg) {
                loading.setValue(false);
                error.setValue(errorMsg);
            }
        });
    }
}

// View：XML 布局（使用 DataBinding）
<layout xmlns:android="http://schemas.android.com/apk/res/android">
    <data>
        <variable
            name="viewModel"
            type="com.example.UserViewModel" />
    </data>
    
    <LinearLayout>
        <EditText
            android:id="@+id/etName"
            android:hint="Name" />
        <EditText
            android:id="@+id/etEmail"
            android:hint="Email" />
        <Button
            android:onClick="@{() -> viewModel.addUser(etName.text.toString(), etEmail.text.toString())}"
            android:text="Add User" />
        <ProgressBar
            android:visibility="@{viewModel.loading ? View.VISIBLE : View.GONE}" />
        <RecyclerView
            android:id="@+id/rvUsers" />
    </LinearLayout>
</layout>

// View：Activity
public class UserActivity extends AppCompatActivity {
    private ActivityUserBinding binding;
    private UserViewModel viewModel;
    private UserAdapter adapter;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        binding = DataBindingUtil.setContentView(this, R.layout.activity_user);
        
        viewModel = ViewModelProviders.of(this).get(UserViewModel.class);
        binding.setViewModel(viewModel);
        binding.setLifecycleOwner(this);
        
        setupRecyclerView();
        observeViewModel();
    }
    
    private void setupRecyclerView() {
        adapter = new UserAdapter(new ArrayList<>());
        binding.rvUsers.setLayoutManager(new LinearLayoutManager(this));
        binding.rvUsers.setAdapter(adapter);
    }
    
    private void observeViewModel() {
        viewModel.getUsers().observe(this, users -> {
            adapter.updateUsers(users);
        });
        
        viewModel.getError().observe(this, error -> {
            Toast.makeText(this, error, Toast.LENGTH_SHORT).show();
        });
    }
}
```

---

## MVVM优缺点

### 优点

1. **数据双向绑定**：View 和 ViewModel 自动同步
2. **代码简洁**：减少样板代码
3. **易于测试**：ViewModel 可以独立测试
4. **生命周期感知**：LiveData 自动处理生命周期
5. **配置变更保持**：ViewModel 在配置变更时保持数据

### 缺点

1. **学习曲线**：需要学习 DataBinding、ViewModel、LiveData
2. **调试困难**：DataBinding 表达式调试较困难
3. **性能问题**：DataBinding 可能影响性能（已优化）
4. **过度绑定**：可能过度使用 DataBinding

---

## MVVM最佳实践

### 1. ViewModel 职责

```java
// ✅ 好的 ViewModel：只处理 UI 逻辑
public class UserViewModel extends ViewModel {
    public void addUser(String name, String email) {
        // 验证输入
        if (name.isEmpty() || email.isEmpty()) {
            error.setValue("Invalid input");
            return;
        }
        // 调用 Repository
        repository.addUser(name, email, callback);
    }
}

// ❌ 不好的 ViewModel：包含业务逻辑
public class UserViewModel extends ViewModel {
    public void addUser(String name, String email) {
        // 业务逻辑不应该在 ViewModel 中
        if (isValidEmail(email)) {
            // 复杂的业务逻辑
        }
    }
}
```

### 2. LiveData 使用

```java
// ✅ 好的做法：使用 MutableLiveData 私有，暴露 LiveData
public class UserViewModel extends ViewModel {
    private MutableLiveData<List<User>> users = new MutableLiveData<>();
    
    public LiveData<List<User>> getUsers() {
        return users; // 返回不可变的 LiveData
    }
}

// ❌ 不好的做法：直接暴露 MutableLiveData
public class UserViewModel extends ViewModel {
    public MutableLiveData<List<User>> users = new MutableLiveData<>();
}
```

### 3. DataBinding 使用

```xml
<!-- ✅ 好的做法：简单的表达式 -->
<TextView android:text="@{user.name}" />
<Button android:onClick="@{() -> viewModel.onClick()}" />

<!-- ❌ 不好的做法：复杂的逻辑 -->
<TextView android:text="@{user.isVip && user.points > 1000 ? `VIP` : `Normal`}" />
<!-- 应该将逻辑移到 ViewModel -->
```

### 4. 避免内存泄漏

```java
// ✅ 好的做法：ViewModel 不持有 View 引用
public class UserViewModel extends ViewModel {
    // ViewModel 不持有 Context、View 等引用
}

// ❌ 不好的做法：ViewModel 持有 View 引用
public class UserViewModel extends ViewModel {
    private Activity activity; // 可能导致内存泄漏
}
```

---

## 面试常见问题

### Q1: 什么是 MVVM 模式？

**答案：**
MVVM（Model-View-ViewModel）是一种软件架构模式：
- **Model**：数据和业务逻辑
- **View**：用户界面（XML 布局）
- **ViewModel**：连接 View 和 Model，处理 UI 逻辑

### Q2: MVVM 和 MVP 的区别？

**答案：**
- **MVP**：View 通过接口与 Presenter 通信，需要手动更新 View
- **MVVM**：View 通过 DataBinding 和 LiveData 自动更新，ViewModel 不持有 View 引用

### Q3: LiveData 的特点？

**答案：**
1. 生命周期感知：自动管理观察者的生命周期
2. 自动更新：数据变化时自动通知观察者
3. 避免内存泄漏：观察者自动取消订阅
4. 配置变更保持：配置变更时数据不丢失

### Q4: ViewModel 的作用？

**答案：**
1. 存储和管理 UI 相关的数据
2. 在配置变更时保持数据
3. 处理 UI 逻辑
4. 不持有 View 引用，避免内存泄漏

### Q5: DataBinding 的优缺点？

**答案：**
- **优点**：减少样板代码、数据双向绑定、代码简洁
- **缺点**：学习曲线、调试困难、可能影响性能

### Q6: 如何防止 ViewModel 内存泄漏？

**答案：**
1. ViewModel 不持有 Context、View 等引用
2. 使用 Application Context 如果需要 Context
3. 在 onCleared 中清理资源
4. 使用 LiveData 自动管理生命周期

---

## 总结

MVVM 是 Android 开发中推荐的架构模式，通过 DataBinding、ViewModel 和 LiveData 实现数据双向绑定和生命周期感知，使代码更简洁、易于测试和维护。

---

*最后更新：2024年*
