Jetpack Room 让SQLite数据库操作变得简单高效

前言

Room 持久性库在 SQLite 的基础上提供了一个抽象层,让用户能够在充分利用 SQLite 的强大功能的同时,获享更强健的数据库访问机制。

在这里插入图片描述

根据这个抽象层,我们不需要编写复杂的数据库操作代码,只需要关心抽象层的设计。

导入依赖

在应用或模块的 build.gradle 文件中添加所需工件的依赖项:

    dependencies {
      def room_version = "2.2.2"//当前官方的Room最新版本

 	implementation "androidx.room:room-runtime:$room_version"
      annotationProcessor "androidx.room:room-compiler:$room_version" 	 // For Kotlin use kapt instead of annotationProcessor

// optional - Kotlin Extensions and Coroutines support for Room
      implementation "androidx.room:room-ktx:$room_version"

// optional - RxJava support for Room
      implementation "androidx.room:room-rxjava2:$room_version"

 // optional - Guava support for Room, including Optional and ListenableFuture
      implementation "androidx.room:room-guava:$room_version"

// Test helpers
      testImplementation "androidx.room:room-testing:$room_version"
    }

如果你是用java构造应用程序,那么请删掉Guava、Kotlin的依赖,这样会让你编译的速度快一些。

Room的几个点

  • 数据库:包含数据库持有者,并作为应用已保留的持久关系型数据的底层连接的主要接入点。

    使用 @Database 注释的类应满足以下条件:
    1. 是扩展 RoomDatabase 的抽象类。
    2. 在注释中添加与数据库关联的实体列表。
    3. 包含具有 0 个参数且返回使用 @Dao 注释的类的抽象方法。
    4. 在运行时,可以通过调用 Room.databaseBuilder()Room.inMemoryDatabaseBuilder() 获取 Database 的实例。

  • Entity:表示数据库中的表。

  • DAO:包含用于访问数据库的方法。

  • AsyncTask: 主线程中直接操作数据库是会报错的,我们可以使用构建AsyncTask子类来使数据库操作在后台执行。

使用Room来操作SQLite数据库

我们测试一个用户的增删改查操作,来了解如何操作SQLite数据库

1. 创建Entity类

注解 作用
@Entity 表明这是一个Entity
@PrimaryKey 表明这个field是主键,autoGenerate = true代表自动生成
@ColumnInfo 表明这是表的列
@Entity
public class User {
    @PrimaryKey(autoGenerate = true)
    private int id;
    @ColumnInfo(name ="username")
    private String username;
    @ColumnInfo(name = "password")
    private String password;

    public User(String username, String password) {
        this.username = username;
        this.password = password;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }
}

2.创建DAO(抽象层接口)

@Dao
public interface UserDao {
    @Insert
    void insertUser(User... user);
    @Update
    void updateUser(User user);
    @Delete
    void deleteUser(User user);

    @Query("DELETE FROM USER")
    void deleteAllUsers();

    @Query("SELECT * FROM USER ORDER BY ID DESC")
    List<User> getAllUsers();
}

需要注意的是,第一个insertUser方法中我们使用User... user作为参数,意义在于我们之后可以放任意个数的参数。

3.创建数据库类

因为我们我们的CRUD都直接依赖于数据库的实例,我们希望在APP的任意处都可以获取唯一的数据库实例,这里使用了单例模式来获取数据库实例。

@Database(entities = {User.class},version = 1,exportSchema = false)
public abstract class UserDatabase extends RoomDatabase {
     private static UserDatabase  userDatabase;
     static UserDatabase getInstance(Context context)
     {
         if(userDatabase==null)
         {
             synchronized (UserDatabase.class)
             {
                 userDatabase=Room.databaseBuilder(context.getApplicationContext(),UserDatabase.class,"user_database").build();
             }
         }
         return  userDatabase;
     }
     //如果你还建了其他的表,也应该声明相关表的接口
    public abstract UserDao getUserDao();
}

5.进行测试

在这里插入图片描述
逻辑代码为

public class MainActivity extends AppCompatActivity {
    UserDatabase userDatabase;
    UserDao userDao;
    Button buttonInsert, buttonClear, buttonDelete, buttonQuery, buttonUpdate;
    TextView textView;

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

        init();
        /**
         * 插入
         */
        buttonInsert.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                userDao.insertUser(new User("user1", "123456"));
            }
        });
        /**
         * 查询所有
         */
        buttonQuery.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                List<User> allUsers = userDao.getAllUsers();
                String str = "";
                for (int i = 0; i < allUsers.size(); i++) {
                    User user = allUsers.get(i);
                    str += user.getId()+"-"+user.getUsername() + "-" + user.getPassword() + "\n";
                }
                textView.setText(str);
            }
        });
        /**
         * 清空所有
         */
        buttonClear.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                userDao.deleteAllUsers();
            }
        });
        /**
         * 删除一个
         */
        buttonDelete.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                User user = new User("user1", "123456");
                user.setId(1);
                userDao.deleteUser(user);
            }
        });
        /**
         * 更新id为1的用户
         */
        buttonUpdate.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                User user = new User("newuser", "123456");
                user.setId(1);
                userDao.updateUser(user);
            }
        });
    }
    private void init() {
        buttonInsert = findViewById(R.id.button_insert);
        buttonDelete = findViewById(R.id.button_delete);
        buttonQuery = findViewById(R.id.button_query);
        buttonClear = findViewById(R.id.button_clear);
        textView = findViewById(R.id.textView2);
        buttonUpdate = findViewById(R.id.button_update);
        userDatabase = UserDatabase.getInstance(this);
        userDao = userDatabase.getUserDao();
    }

}

当我满心欢喜想要测试CRUD时,bug来了,run爆了这样一条异常

java.lang.IllegalStateException: Cannot access database on the main thread since it may potentially lock the UI for a long period of time.

大概意思就是说你不可以在主线程中操作数据库,正如在前面所说,我们需要AsyncTask类,从而在后台线程中执行数据库操作。

6.新建相关方法的AsyncTask类

这里以使用改造AsyncTask类insert方法为例,当然对于本例我们应该亦需要新建update、delete等方法的AsyncTask类。

//三个参数分别为 操作的对象、进度、结果
public class  InsertAsyncTasks extends AsyncTask<User,Void,Void>
    {
        private UserDao userDao;

        public InsertAsyncTasks(UserDao userDao) {
            this.userDao = userDao;
        }

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

        @Override
        protected void onProgressUpdate(Void... values) {
            //进度发生更新时
            super.onProgressUpdate(values);
        }

        @Override
        protected void onPreExecute() {
            //执行之前
            super.onPreExecute();
        }
    }

这样我们在Activity中的插入操作代码就应该这样写,即new一个InsertAsyncTasks对象,并执行execute()方法

   /**
	* 插入
	*/
        buttonInsert.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                new InsertAsyncTasks(userDao).execute();
              //  userDao.insertUser(new User("user1", "123456"));
            }
        });

数据的插入是成功的,但是,有一个问题,我们的数据操作都在Activity中完成,是Activty的职责是管理生命周期。我们需要引入Repository概念来解决这个问题。

Repository概念

Repository并不是一个Room中的组件,而是一个概念,从而把数据库操作分离出来。

public class UserRepository  {

    private UserDao userDao;

    public UserRepository(Context context) {
        UserDatabase userDatabase=UserDatabase.getInstance(context);
        userDao=userDatabase.getUserDao();


    }
    void insertUser(User... users)
    {
        new InsertAsyncTasks(userDao).execute(users);
    }
}

上面代码依旧是以insert为例子,所以在Activity中我们便可以这样操作

/**
         * 插入
         */
        buttonInsert.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                User user=new User("user1", "123456");
                userRepository.insertUser(user);
            }
        });
发布了243 篇原创文章 · 获赞 106 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/weixin_43889841/article/details/104142550