android data 文件夹作用

发布于:2025-08-19 ⋅ 阅读:(17) ⋅ 点赞:(0)

一 data 文件夹作用

在 Android 项目架构中,data 文件夹(或称为“数据层”)是负责数据的获取、存储、转换和管理的核心模块,是应用与底层数据源(如网络、数据库、本地文件等)交互的“桥梁”。它的核心职责是为上层(尤其是领域层 domain)提供干净、可靠的数据,同时屏蔽具体数据源的细节(比如是从网络接口还是本地数据库获取数据)。

data 文件夹的核心作用

  1. 统一管理数据源
    应用的数据来源通常是多样的(网络 API、本地数据库、SharedPreferences、文件等),data 层会集中管理这些数据源,对外提供统一的访问接口,让上层(领域层)无需关心数据来自哪里。

  2. 数据转换与适配
    原始数据(如网络接口返回的 JSON 结构、数据库表结构)往往不直接适合业务使用,data 层会将这些原始数据(entity)转换为适合上层处理的模型(model),比如:

    • 把网络接口的时间戳字段转换为格式化的日期字符串
    • 合并本地数据库和网络的零散数据为完整的业务模型
  3. 数据持久化
    负责数据的本地存储逻辑,比如用 Room 操作数据库、用 DataStore/SharedPreferences 存储轻量数据,确保应用在离线时也能访问关键数据。

  4. 实现领域层的抽象接口
    数据层会实现领域层(domain)定义的 Repository 接口(抽象),通过这种“依赖倒置”的方式,让领域层与具体数据源解耦(领域层只依赖抽象,不依赖具体实现)。

data 文件夹的典型内部结构

data 层的包结构通常按“数据源类型”和“功能职责”划分,常见结构如下:

com.example.app.data/
├─ entity/               // 原始数据实体(与数据源一一对应)
│  ├─ local/             // 本地数据库实体(如 Room 的 @Entity 类)
│  │  └─ UserEntity.java  // 对应数据库中的 user 表
│  └─ remote/            // 网络接口实体(如 Retrofit 解析的 JSON 类)
│     └─ UserRemote.java  // 对应网络接口返回的用户数据结构
│
├─ model/                // 数据层内部的模型(用于转换后的数据传递)
│  └─ UserDetailModel.java  // 合并本地和网络数据后的模型
│
├─ repository/           // 仓库实现类(实现 domain 层的 Repository 接口)
│  └─ UserRepositoryImpl.java  // 实现 domain 定义的 UserRepository 接口
│
├─ datasource/           // 数据源操作类(直接与底层交互)
│  ├─ local/             // 本地数据源(如数据库操作)
│  │  └─ UserLocalDataSource.java  // 用 Room 操作本地用户数据
│  └─ remote/            // 远程数据源(如网络请求)
│     └─ UserRemoteDataSource.java  // 用 Retrofit 调用用户相关接口
│
└─ mapper/               // 数据转换工具(Entity ↔ Model)
   └─ UserMapper.java  // 将 UserEntity 转换为 UserDetailModel

data 层的核心组件

  1. Entity(实体)
    直接映射数据源的原始数据结构,不包含业务逻辑,仅作为数据的“容器”。例如:

    • 网络接口返回的 JSON 字段会被解析为 remote 包下的 XXXRemote
    • 数据库表结构会被定义为 local 包下的 @Entity 类(Room)
  2. DataSource(数据源)
    直接操作底层数据源的类,封装了具体的读写逻辑:

    • LocalDataSource:操作本地数据库、文件等,如 UserLocalDataSource 包含 getUserFromDB()saveUserToDB() 等方法
    • RemoteDataSource:调用网络接口,如 UserRemoteDataSource 包含 fetchUserFromApi() 等方法
  3. Repository Impl(仓库实现)
    实现领域层(domain)定义的 Repository 接口,协调多个数据源(本地+远程)的交互,是数据层对外的“统一出口”。例如:

    // 实现 domain 层的 UserRepository 接口
    public class UserRepositoryImpl implements UserRepository {
        private final UserLocalDataSource localDataSource;
        private final UserRemoteDataSource remoteDataSource;
        
        @Override
        public UserDetail getUserId(String userId) {
            // 先查本地缓存
            UserEntity localUser = localDataSource.getUser(userId);
            if (localUser != null) {
                return UserMapper.toDomainModel(localUser);
            }
            // 本地没有则请求网络
            UserRemote remoteUser = remoteDataSource.fetchUser(userId);
            // 缓存到本地
            localDataSource.saveUser(UserMapper.toEntity(remoteUser));
            return UserMapper.toDomainModel(remoteUser);
        }
    }
    
  4. Mapper(映射器)
    负责数据格式的转换,将 Entity(原始数据)转换为 Model(业务模型),或转换为领域层需要的 Domain Model。例如:

    public class UserMapper {
        // 网络实体 → 领域模型
        public static UserDomain toDomainModel(UserRemote remote) {
            return new UserDomain(
                remote.getId(),
                remote.getName(),
                calculateAge(remote.getBirthday()) // 转换时间戳为年龄
            );
        }
    }
    

data 层与其他层的关系

  • 依赖领域层data 层会依赖 domain 层定义的 Repository 接口和 Domain Model,但不会被领域层依赖(符合依赖倒置原则)。
  • 被上层调用:领域层的 UseCase 通过调用 data 层实现的 Repository 接口获取数据,无需关心数据来自本地还是网络。
  • 不依赖 UI 层data 层专注于数据处理,不涉及任何 UI 相关的类(如 ActivityViewModel),确保可独立测试。

总结

data 文件夹是 Android 项目的“数据中枢”,负责:

  1. 管理所有数据源(本地/远程)的读写
  2. 将原始数据转换为适合业务的模型
  3. 实现领域层的抽象接口,为上层提供统一的数据访问入口

通过 data 层的封装,上层业务逻辑可以专注于处理业务规则,而无需关心数据的具体来源和格式,这是实现“高内聚、低耦合”架构的核心环节。

modeldomainentityui 的区别

在Android项目开发中,modeldomainentityui 是常见的包结构划分,其核心目的是通过职责分离实现代码的可维护性、可测试性和扩展性。不同包对应不同的功能层次,下面详细解释它们的区别和使用场景。

一、四个包的核心区别与职责

1. entity:数据实体层(最底层,原始数据载体)

核心职责:存储和传递“原始数据”,对应数据源的直接映射(如数据库表、网络接口返回的原始数据),不包含业务逻辑。
本质:数据的“最小单元”,是数据在系统中的“原始形态”。

具体场景

  • 数据库实体:如 Room 注解的 @Entity 类(对应数据库表结构)。
  • 网络实体:如 Retrofit 接口返回的 JSON 解析类(直接映射接口字段,无额外处理)。
  • 本地存储实体:如 SharedPreferences 存储的原始数据模型。

特点

  • 字段与数据源(数据库/接口)严格对应,不做业务转换。
  • 无复杂逻辑,仅包含 getter/setter 或数据校验(如非空判断)。
2. model:数据模型层(中间层,业务适配数据)

核心职责:对 entity 进行转换、封装或扩展,提供“适合业务场景”的数据模型(如 UI 展示、业务计算所需的数据格式)。
本质:原始数据(entity)的“加工品”,适配特定业务需求。

具体场景

  • UI 展示模型:将 UserEntity(包含 birthTimestamp 时间戳)转换为 UserModel(包含 age 年龄字段,便于 UI 直接显示)。
  • 业务计算模型:将多个 OrderEntity 聚合为 OrderSummaryModel(包含总金额、订单数量等计算后的数据)。
  • 跨数据源整合模型:合并本地数据库 UserEntity 和网络接口 UserExtraEntityUserDetailModel

特点

  • 依赖 entity,通过转换工具(如 Mapper 类)生成。
  • 包含数据转换逻辑(如时间戳转年龄、金额格式化),但不包含核心业务逻辑(如订单状态判断)。
3. domain:领域层(核心层,业务逻辑中枢)

核心职责:封装核心业务逻辑、用例和领域模型,是系统的“大脑”,独立于具体框架(不依赖 Android 类)。
本质:定义“业务规则”,协调数据的获取、处理和流转。

具体场景

  • 用例(UseCase):如 GetUserDetailUseCase(封装“获取用户详情”的业务流程:调用仓库获取数据→校验→返回结果)。
  • 领域模型(Domain Model):抽象的业务实体(如 User 领域模型,包含业务核心属性,与数据源无关)。
  • 仓库接口(Repository Interface):定义数据获取规范(如 UserRepository 接口,由数据层实现)。
  • 业务工具类:如 OrderStatusCalculator(判断订单状态的核心逻辑)。

特点

  • 不依赖 Android 框架(无 ContextActivity 等类),可独立测试。
  • 是连接数据层(entity)和表现层(ui)的桥梁,不关心数据从哪里来(本地/网络),只关心如何处理。
4. ui:表现层(最上层,用户交互)

核心职责:负责用户界面展示和交互,接收用户输入并反馈结果,依赖领域层获取数据。
本质:数据的“展示窗口”和用户交互的“入口”。

具体场景

  • 界面组件:ActivityFragmentCompose 页面等。
  • 视图模型:ViewModel(管理 UI 数据,与领域层交互获取数据)。
  • 交互相关:适配器(Adapter)、自定义 View、点击事件处理器等。

特点

  • 依赖 domain 层(通过 ViewModel 调用 UseCase)或 model 层(直接使用 UI 模型)。
  • 不处理核心业务逻辑,仅做数据展示和用户输入传递。

二、Android 项目建包建议(结合架构分层)

在实际开发中,包结构通常与架构(如 Clean Architecture、MVVM)结合,核心原则是**“高内聚、低耦合”**,即每个包只做一类事,层与层通过接口交互。

推荐的包结构示例(以 Clean Architecture 为基础)
com.example.app/
├─ data/                  // 数据层:处理数据获取和存储
│  ├─ entity/             // 原始数据实体(数据库、网络、本地存储)
│  │  ├─ local/           // 本地数据库实体(Room Entity)
│  │  └─ remote/          // 网络接口实体(Retrofit 解析类)
│  ├─ model/              // 数据层内部模型(可选,数据转换用)
│  └─ repository/         // 仓库实现(实现 domain 层的 Repository 接口)
│
├─ domain/                // 领域层:核心业务逻辑
│  ├─ model/              // 领域模型(抽象业务实体,与数据源无关)
│  ├─ repository/         // 仓库接口(定义数据获取规范)
│  └─ useCase/            // 用例(封装具体业务流程)
│
├─ ui/                    // 表现层:UI 展示和交互
│  ├─ activity/           // Activity 组件
│  ├─ fragment/           // Fragment 组件
│  ├─ compose/            // Compose 页面(如用 Compose 开发)
│  ├─ adapter/            // 列表适配器
│  └─ viewModel/          // ViewModel(管理 UI 数据,调用 UseCase)
│
└─ common/                // 通用工具(全局工具类、常量等)
各包的协作流程(以“获取用户详情”为例)
  1. UI 层触发需求:用户在 UserDetailActivity 点击“查看详情”,UserDetailViewModel 接收事件。
  2. 调用领域层用例ViewModel 调用 domain.useCase.GetUserDetailUseCase
  3. 领域层协调数据GetUserDetailUseCase 调用 domain.repository.UserRepository 接口(不关心具体实现)。
  4. 数据层实现接口data.repository.UserRepositoryImpl 实现接口,从本地数据库获取 entity.local.UserEntity,从网络获取 entity.remote.UserExtraEntity
  5. 数据转换为模型:数据层将 UserEntityUserExtraEntity 转换为 data.model.UserDetailModel,返回给领域层。
  6. 领域层处理业务:用例对 UserDetailModel 进行业务校验(如判断会员状态),转换为 domain.model.User 领域模型。
  7. UI 层展示数据ViewModeldomain.model.User 转换为 ui.model.UserUIModel(如格式化生日为年龄),通过 LiveData 通知 UI 刷新。

三、注意事项

  1. 避免职责混淆

    • 不要在 entity 中写业务逻辑(如计算年龄),这是 modeldomain 的职责。
    • 不要在 ui 层(如 ViewModel)中写核心业务逻辑,应放在 domainUseCase 中。
    • domain 层不依赖 Android 框架,确保可独立单元测试(用 JUnit 而非 InstrumentedTest)。
  2. 灵活调整粒度

    • 小型项目可简化结构,例如将 entitymodel 合并(如果数据无需复杂转换)。
    • 大型项目可进一步细分,如 ui 层按功能模块拆分(ui.userui.order)。
  3. 依赖方向
    严格遵循“上层依赖下层,下层不依赖上层”:

    • ui 依赖 domainmodel,但 domainmodel 不依赖 ui
    • domain 依赖自身的 repository 接口,不依赖 data 层的实现。
    • data 层依赖 domain 的接口,实现数据获取逻辑。

通过合理划分这四个包,Android 项目可以实现“业务逻辑与 UI 分离、数据与业务分离”,大幅提升代码的可维护性和扩展性,尤其适合中大型项目。


网站公告

今日签到

点亮在社区的每一天
去签到