Android Room的使用详解

Android Room 在 Java 中的详细使用指南,涵盖从依赖配置到实际代码实现的完整流程:


一、添加依赖项

build.gradle 文件中添加 Room 的依赖项(Java 配置):

kotlin 复制代码
gradle
深色版本
dependencies {
    def room_version = "2.6.1" // 使用最新稳定版本

    // Room 运行时库
    implementation "androidx.room:room-runtime:$room_version"
    // Java 注解处理器
    annotationProcessor "androidx.room:room-compiler:$room_version"

    // 可选:RxJava2 支持
    implementation "androidx.room:room-rxjava2:$room_version"
    // 可选:测试支持
    androidTestImplementation "androidx.room:room-testing:$room_version"
}

二、定义数据实体(Entity)

使用 @Entity 注解定义数据库表对应的 Java 类。字段默认映射为表的列,可自定义列名或添加索引。

示例(Java):

typescript 复制代码
java
深色版本
import androidx.room.*;

@Entity(tableName = "users",
        indices = {@Index(value = {"last_name", "address"}, unique = true)})
public class User {
    @PrimaryKey(autoGenerate = true)
    private int id;

    @ColumnInfo(name = "first_name")
    private String firstName;

    @ColumnInfo(name = "last_name")
    private String lastName;

    private int age;

    private String address;

    // 构造方法
    public User(String firstName, String lastName, int age, String address) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.age = age;
        this.address = address;
    }

    // Getter 和 Setter 方法
    public int getId() { return id; }
    public void setId(int id) { this.id = id; }

    public String getFirstName() { return firstName; }
    public void setFirstName(String firstName) { this.firstName = firstName; }

    public String getLastName() { return lastName; }
    public void setLastName(String lastName) { this.lastName = lastName; }

    public int getAge() { return age; }
    public void setAge(int age) { this.age = age; }

    public String getAddress() { return address; }
    public void setAddress(String address) { this.address = address; }
}

关键注解说明:

  • @Entity(tableName = "users"): 定义表名。
  • @PrimaryKey(autoGenerate = true): 主键,并启用自增。
  • @ColumnInfo(name = "column_name"): 自定义列名(可选)。
  • @Index: 定义索引,提升查询性能。

三、定义数据访问对象(DAO)

DAO 是访问数据库的接口,通过注解声明 SQL 操作方法。

示例(Java):

java 复制代码
java
深色版本
import androidx.room.*;
import java.util.List;
import android.database.Cursor;

@Dao
public interface UserDao {
    @Query("SELECT * FROM users")
    List<User> getAllUsers();

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    void insertUser(User user);

    @Update
    int updateUser(User user);

    @Delete
    int deleteUser(User user);

    @Query("SELECT * FROM users WHERE last_name LIKE :lastName")
    List<User> searchByLastName(String lastName);
}

关键注解说明:

  • @Query("SQL_STATEMENT"): 执行自定义 SQL 查询。
  • @Insert@Update@Delete: 分别对应插入、更新、删除操作。
  • onConflict = OnConflictStrategy.REPLACE: 冲突解决策略(如主键冲突时替换数据)。

四、创建数据库类(RoomDatabase)

数据库类是 Room 的核心,负责管理数据库的创建和 DAO 的获取。

示例(Java):

scala 复制代码
java
深色版本
import android.content.Context;
import androidx.room.Database;
import androidx.room.Room;
import androidx.room.RoomDatabase;

@Database(entities = {User.class}, version = 1, exportSchema = false)
public abstract class AppDatabase extends RoomDatabase {
    public abstract UserDao userDao();

    private static volatile AppDatabase INSTANCE;

    public static AppDatabase getDatabase(final Context context) {
        if (INSTANCE == null) {
            synchronized (AppDatabase.class) {
                if (INSTANCE == null) {
                    INSTANCE = Room.databaseBuilder(context.getApplicationContext(),
                            AppDatabase.class, "app_database")
                            .build();
                }
            }
        }
        return INSTANCE;
    }
}

关键点说明:

  • @Database(entities = {User.class}, version = 1): 定义实体类和数据库版本号。
  • Room.databaseBuilder(...): 构建数据库实例。
  • 单例模式确保数据库全局唯一。

五、在 ViewModel 中使用 Room

结合 ViewModelLiveData 实现数据与 UI 的分离,并支持生命周期感知的数据更新。

示例(Java):

scala 复制代码
java
深色版本
import android.app.Application;
import androidx.annotation.NonNull;
import androidx.lifecycle.AndroidViewModel;
import androidx.lifecycle.LiveData;
import java.util.List;

public class UserViewModel extends AndroidViewModel {
    private final UserDao userDao;
    private final LiveData<List<User>> allUsers;

    public UserViewModel(@NonNull Application application) {
        super(application);
        AppDatabase database = AppDatabase.getDatabase(application);
        userDao = database.userDao();
        allUsers = userDao.getAllUsers();
    }

    public LiveData<List<User>> getAllUsers() {
        return allUsers;
    }

    public void insertUser(User user) {
        new InsertUserAsyncTask(userDao).execute(user);
    }

    public void deleteUser(User user) {
        new DeleteUserAsyncTask(userDao).execute(user);
    }

    // 使用 AsyncTask 在后台线程执行数据库操作
    private static class InsertUserAsyncTask extends AsyncTask<User, Void, Void> {
        private final UserDao userDao;

        private InsertUserAsyncTask(UserDao userDao) {
            this.userDao = userDao;
        }

        @Override
        protected Void doInBackground(User... users) {
            userDao.insertUser(users[0]);
            return null;
        }
    }

    private static class DeleteUserAsyncTask extends AsyncTask<User, Void, Void> {
        private final UserDao userDao;

        private DeleteUserAsyncTask(UserDao userDao) {
            this.userDao = userDao;
        }

        @Override
        protected Void doInBackground(User... users) {
            userDao.deleteUser(users[0]);
            return null;
        }
    }
}

关键点说明:

  • ViewModel: 用于管理 UI 相关的数据,避免 Activity/Fragment 中的直接数据库操作。
  • AsyncTask: 在后台线程执行数据库操作(Room 不允许在主线程操作数据库)。
  • LiveData: 自动更新 UI 当数据变化时。

六、初始化和使用数据库

在应用中初始化数据库并调用 DAO 方法:

ini 复制代码
java
深色版本
// 获取数据库实例
AppDatabase db = AppDatabase.getDatabase(context);
UserDao userDao = db.userDao();

// 插入数据
User user = new User("John", "Doe", 30, "123 Main St");
userDao.insertUser(user);

// 查询数据
List<User> users = userDao.getAllUsers();
for (User u : users) {
    Log.d("User", u.getFirstName() + " " + u.getLastName());
}

七、数据库迁移(Migration)

当修改了实体类(如添加/删除字段)时,需要处理数据库迁移:

示例(Java):

scala 复制代码
java
深色版本
// 添加新字段 "email" 到 User 实体类
@Database(entities = {User.class}, version = 2)
public abstract class AppDatabase extends RoomDatabase {
    // ...其他代码不变
}

// 创建 Migration 对象
static final Migration MIGRATION_1_2 = new Migration(1, 2) {
    @Override
    public void migrate(SupportSQLiteDatabase database) {
        database.execSQL("ALTER TABLE users ADD COLUMN email TEXT");
    }
};

// 构建数据库时添加迁移策略
INSTANCE = Room.databaseBuilder(context.getApplicationContext(),
        AppDatabase.class, "app_database")
        .addMigration(MIGRATION_1_2)
        .build();

八、注意事项

  1. 主线程限制
    Room 不允许在主线程执行数据库操作(会抛出 IllegalStateException)。必须使用后台线程(如 AsyncTaskThreadExecutorService)。
  2. 响应式数据
    如果 DAO 方法返回 LiveDataFlow,Room 会自动在后台线程查询并通知 UI 更新。
  3. 版本控制
    修改数据库结构时必须更新 @Databaseversion,并提供迁移策略(Migration)。
  4. 数据清理
    使用 .fallbackToDestructiveMigration() 可强制删除旧数据库并重新创建(仅限开发环境)。

九、完整项目结构

less 复制代码
深色版本
app/
├── build.gradle
├── src/main/java/
│   ├── com.example.roomdemo/
│   │   ├── entity/
│   │   │   └── User.java          // 实体类
│   │   ├── dao/
│   │   │   └── UserDao.java       // DAO 接口
│   │   ├── database/
│   │   │   └── AppDatabase.java   // 数据库类
│   │   ├── viewmodel/
│   │   │   └── UserViewModel.java // ViewModel
│   │   └── MainActivity.java      // 主界面

通过以上步骤,你可以在 Java 项目中高效使用 Room 实现本地数据库操作。

相关推荐
安东尼肉店2 小时前
Android compose屏幕适配终极解决方案
android
2501_916007473 小时前
HTTPS 抓包乱码怎么办?原因剖析、排查步骤与实战工具对策(HTTPS 抓包乱码、gzipbrotli、TLS 解密、iOS 抓包)
android·ios·小程序·https·uni-app·iphone·webview
feiyangqingyun4 小时前
基于Qt和FFmpeg的安卓监控模拟器/手机摄像头模拟成onvif和28181设备
android·qt·ffmpeg
用户2018792831678 小时前
ANR之RenderThread不可中断睡眠state=D
android
煤球王子8 小时前
简单学:Android14中的Bluetooth—PBAP下载
android
小趴菜82278 小时前
安卓接入Max广告源
android
齊家治國平天下8 小时前
Android 14 系统 ANR (Application Not Responding) 深度分析与解决指南
android·anr
ZHANG13HAO8 小时前
Android 13.0 Framework 实现应用通知使用权默认开启的技术指南
android
【ql君】qlexcel8 小时前
Android 安卓RIL介绍
android·安卓·ril
写点啥呢8 小时前
android12解决非CarProperty接口深色模式设置后开机无法保持
android·车机·aosp·深色模式·座舱