Android 架构(千字长文)

Android 架构:从零开始理解应用的骨架

在开发 Android 应用时,很多人一开始只关注“功能能不能实现”,比如按钮点击跳转页面、数据从网络获取后显示在列表里。但当项目变大、团队人数增多,你会发现代码越来越难维护,修改一个功能可能牵一发而动全身。这时候,你就会意识到:Android 架构的重要性,就像盖房子要先有设计图一样,应用也需要清晰的结构来支撑长期发展。

我们常说的 Android 架构,指的是一套指导应用开发的分层模式,它帮助我们把“数据”、“界面”、“逻辑”拆开,让每个部分各司其职,互不干扰。今天,我们就从零开始,一步步认识 Android 架构的核心思想,并通过真实代码案例,手把手带你搭建一个结构清晰的应用。


为什么需要 Android 架构?

想象你正在组装一台复杂的拼图。如果所有碎片都堆在一个盒子里,你根本不知道哪块该放哪里。而有了清晰的架构,就像是把拼图按区域分好:背景、人物、建筑……每一块都有明确的位置和职责。

在 Android 开发中,没有架构的应用就像一锅乱炖——UI 代码里夹杂着网络请求、数据库操作、业务逻辑。这样的代码很难测试、难以复用,更别提多人协作了。

因此,Android 架构的核心目标是:

  • 解耦:让不同模块之间不直接依赖
  • 可测试性:逻辑部分能独立运行测试
  • 可维护性:修改一处,不影响其他部分
  • 可扩展性:新增功能时,不影响原有结构

Model-View-ViewModel(MVVM)架构详解

目前最主流的 Android 架构模式是 MVVM。它把应用分成三个主要部分:Model、View 和 ViewModel。

Model:数据的源头

Model 负责数据的获取与存储,比如从网络拉取用户信息、读写本地数据库、处理业务规则等。

// UserDataSource.java
public class UserDataSource {
    // 模拟从网络获取用户数据
    public LiveData<User> getUserFromNetwork(String userId) {
        MutableLiveData<User> result = new MutableLiveData<>();
        
        // 模拟网络延迟
        new Handler(Looper.getMainLooper()).postDelayed(() -> {
            User user = new User();
            user.setId(userId);
            user.setName("张三");
            user.setEmail("zhangsan@example.com");
            result.setValue(user); // 通知观察者数据已更新
        }, 1500);

        return result;
    }
}

注释:这里使用 LiveData 是为了实现数据的自动通知机制。当数据变化时,View 会自动刷新,无需手动调用 UI 更新。

View:界面的展示者

View 负责显示数据和响应用户操作。在 MVVM 中,View 通常是一个 ActivityFragment,但它不直接处理数据逻辑。

// MainActivity.java
public class MainActivity extends AppCompatActivity {
    private TextView tvName;
    private TextView tvEmail;
    private Button btnLoad;

    // ViewModel 实例
    private UserViewModel viewModel;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // 初始化 UI 组件
        tvName = findViewById(R.id.tv_name);
        tvEmail = findViewById(R.id.tv_email);
        btnLoad = findViewById(R.id.btn_load);

        // 获取 ViewModel 实例(通过 ViewModelProvider)
        viewModel = new ViewModelProvider(this).get(UserViewModel.class);

        // 监听 ViewModel 中的数据变化
        viewModel.getUser().observe(this, user -> {
            if (user != null) {
                tvName.setText(user.getName());
                tvEmail.setText(user.getEmail());
            }
        });

        // 点击按钮触发数据加载
        btnLoad.setOnClickListener(v -> viewModel.loadUser("1001"));
    }
}

注释:observe() 方法监听 LiveData 的变化。当 ViewModel 中的数据更新时,UI 会自动刷新,这是 MVVM 的核心优势之一。

ViewModel:连接 View 与 Model 的桥梁

ViewModel 是 MVVM 的核心,它负责管理 UI 相关的数据,且不会因屏幕旋转等配置变化而被销毁。

// UserViewModel.java
public class UserViewModel extends ViewModel {
    private UserDataSource dataSource;
    private MutableLiveData<User> userLiveData;

    public UserViewModel() {
        dataSource = new UserDataSource();
        userLiveData = new MutableLiveData<>();
    }

    // 提供给 View 的数据访问接口
    public LiveData<User> getUser() {
        return userLiveData;
    }

    // 加载用户数据的方法
    public void loadUser(String userId) {
        // 从数据源获取数据
        LiveData<User> data = dataSource.getUserFromNetwork(userId);
        
        // 将数据传递给 LiveData
        data.observeForever(user -> {
            userLiveData.setValue(user); // 更新 UI 数据
        });
    }
}

注释:observeForever 用于长期监听数据,但要注意在合适时机移除监听,避免内存泄漏。在实际项目中,建议用 observe() 并传入生命周期所有者(如 Activity)。


架构分层:清晰的职责划分

为了进一步提升可维护性,我们可以把 Android 架构拆分为更细的层级:

层级 职责 示例
Presentation Layer(表现层) 管理 UI 逻辑、用户交互 Activity、Fragment、ViewModel
Domain Layer(业务逻辑层) 处理核心业务规则 UseCase、Repository 接口
Data Layer(数据层) 负责数据获取与存储 Repository 实现、API 接口、Room 数据库

这种分层方式,让代码结构更清晰,也便于单元测试。


使用 Repository 模式统一数据访问

在复杂项目中,数据可能来自多个地方:网络、本地数据库、缓存等。这时引入 Repository 模式就非常必要。

// UserRepository.java
public class UserRepository {
    private UserRemoteDataSource remoteDataSource;
    private UserLocalDataSource localDataSource;

    public UserRepository(UserRemoteDataSource remote, UserLocalDataSource local) {
        this.remoteDataSource = remote;
        this.localDataSource = local;
    }

    // 统一入口:先查本地,再查网络
    public LiveData<User> getUser(String userId) {
        MutableLiveData<User> result = new MutableLiveData<>();

        // 先从本地加载
        localDataSource.getUser(userId).observeForever(user -> {
            if (user != null) {
                result.setValue(user); // 本地有数据,先显示
            } else {
                // 本地无数据,从网络获取
                remoteDataSource.getUser(userId).observeForever(networkUser -> {
                    if (networkUser != null) {
                        // 保存到本地
                        localDataSource.saveUser(networkUser);
                        result.setValue(networkUser);
                    }
                });
            }
        });

        return result;
    }
}

注释:Repository 是数据的“总调度员”,它决定从哪里获取数据,如何合并,以及是否缓存。它屏蔽了数据源的复杂性,让上层代码无需关心“数据从哪来”。


实际项目中的最佳实践

在真实项目中,建议遵循以下原则:

  1. ViewModel 只负责 UI 状态管理,不包含业务逻辑
    业务逻辑应封装在 UseCaseInteractor 中。

  2. 避免在 Activity 中写太多逻辑
    尽量把事件处理交给 ViewModel,保持 Activity 简洁。

  3. 使用依赖注入(如 Hilt)管理组件
    避免手动 new 对象,提升可测试性和可维护性。

  4. 合理使用 LiveData 和 Flow
    Flow 是 Kotlin 协程的响应式流,更适合复杂异步场景。


总结:架构不是“为了用而用”

很多初学者会问:“我一个小应用,有必要搞这么复杂吗?”
答案是:早一点建立架构意识,比后期重构要省力得多

即使是一个简单的“显示用户信息”的 App,只要从一开始就按 MVVM 思想设计,未来加入登录、缓存、离线功能时,你不会手忙脚乱。

Android 架构不是一套死板的规则,而是一种思维方式——把复杂问题拆解成可管理的部分。当你能清晰地说出“这个类负责什么”、“数据从哪里来、到哪里去”,你就已经迈入了专业开发者的行列。

记住:代码的可读性,永远比“能跑”更重要
从今天开始,用架构武装你的 Android 项目吧。