Android开发之Room(Java)

Room 在 SQLite 上提供了一个抽象层,以便在充分利用 SQLite 的强大功能的同时,能够流畅地访问数据库。

处理大量结构化数据的应用可极大地受益于在本地保留这些数据。最常见的用例是缓存相关数据。这样,当设备无法访问网络时,用户仍可在离线状态下浏览相应内容。设备之后重新连接到网络后,用户发起的所有内容更改都会同步到服务器。

官方建议使用Room,而不是SQLite

使用Room库要在应用或模块的build.gradle文件中添加依赖:

    dependencies {
      def room_version = "2.2.3"

      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"
    }

Room包括3个主要组件:

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

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

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

它们之间的关系如下
在这里插入图片描述

使用Room实体定义数据

使用示例:

    @Entity(primaryKeys = {"firstName", "lastName"})
    public class User {
		//@PrimaryKey
		//public int id;
		
        public String firstName;
        public String lastName;
    }

定义主键如上有两种方式
关于字段的访问权限:要保留某个字段,Room 必须拥有该字段的访问权限。您可以将某个字段设为公开字段,也可以为其提供 getter 和 setter。如果您使用 getter 和 setter 方法,则请注意,这些方法需遵循 Room 中的 JavaBeans 规范。
更多详情请参见

定义对象之间的关系

定义一对多关系
即使您不能使用直接关系,Room 仍允许您定义实体之间的外键约束。

例如,如果存在另一个名为 Book 的实体,您可以使用 @ForeignKey 注释定义该实体与 User 实体的关系,如以下代码段所示:

    @Entity(foreignKeys = @ForeignKey(entity = User.class,
                                      parentColumns = "id",
                                      childColumns = "user_id"))
    public class Book {
        @PrimaryKey public int bookId;

        public String title;

        @ColumnInfo(name = "user_id") public int userId;
    }

在 @ForeignKey 注释中添加 onDelete = CASCADE,可以实现级联删除
更多应用请参见

在数据库中创建视图

使用RoomDAO访问数据

@Insert,@Update,@Delete示例:

    @Dao
    public interface MyDao {
        @Insert(onConflict = OnConflictStrategy.REPLACE)
        public void insertUsers(User... users);

		@Update
        public void updateUsers(User... users);

		@Delete
        public void deleteUsers(User... users);
    }

查询信息:

@Query 是 DAO 类中使用的主要注释。它允许您对数据库执行读/写操作
简单查询示例:

    @Dao
    public interface MyDao {
        @Query("SELECT * FROM user")//括号内可以是任意其他SQL语句
        public User[] loadAllUsers();
    }

在方法返回对象与查询结果字段不匹配时会发出警告
可观察查询: 查询方法对应的返回指声明为LiveData<?>,例如:

    @Dao
    public interface MyDao {
        @Query("SELECT first_name, last_name FROM user WHERE region IN (:regions)")
        public LiveData<List<User>> loadUsersFromRegionsSync(List<String> regions);
    }

这样,应用的界面就会在数据发生变化时自动更新了
更多数据库访问相关请参见

最后一步:编写数据库类

使用 @Database 注释的类应满足以下条件:

  • 是扩展 RoomDatabase 的抽象类。
  • 在注释中添加与数据库关联的实体列表。
  • 包含具有 0 个参数且返回使用 @Dao 注释的类的抽象方法。

在运行时,您可以通过调用 Room.databaseBuilder() 或 Room.inMemoryDatabaseBuilder() 获取

示例模板:

 // Song and Album are classes annotated with @Entity.
 @Database(version = 1, entities = {Song.class, Album.class})
 abstract class MusicDatabase extends RoomDatabase {
   // SongDao is a class annotated with @Dao.
   abstract public SongDao getSongDao();
   // AlbumDao is a class annotated with @Dao.
   abstract public ArtistDao getArtistDao();
   // SongAlbumDao is a class annotated with @Dao.
   abstract public SongAlbumDao getSongAlbumDao();
 }

在上面的例子中有两个表(有entities属性声明)和三个DAO(对应三个获取DAO的方法)

两个获取方法:

public static Builder databaseBuilder (Context context,
Class klass,
String name)

参数/返回名含义
context数据库的上下文。这通常是应用程序上下文。
kclass用注释Database和扩展 的抽象类RoomDatabase。
name数据库文件的名称。
Builder一个RoomDatabaseBuilder实例,用于创建数据库

public static Builder inMemoryDatabaseBuilder (Context context,
Class klass)

参数/返回名含义
context数据库的上下文。这通常是应用程序上下文。
kclass用注释Database和扩展 的抽象类RoomDatabase。
Builder一个RoomDatabaseBuilder实例,用于创建数据库

完成以上步骤,就可以在应用中获取database实例来对数据库进行操作了

实践案例

User

package com.example.demoroom;

import androidx.room.ColumnInfo;
import androidx.room.Entity;
import androidx.room.PrimaryKey;

@Entity
public class User {
    @PrimaryKey
    public int uid;

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

    @ColumnInfo(name = "last_name")
    public String lastName;
}

UserDAO

package com.example.demoroom;

import androidx.room.Dao;
import androidx.room.Delete;
import androidx.room.Insert;
import androidx.room.Query;

import java.util.List;

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

    @Query("SELECT * FROM user WHERE uid IN (:userIds)")
    List<User> loadAllByIds(int[] userIds);

    @Query("SELECT * FROM user WHERE first_name LIKE :first AND " +
            "last_name LIKE :last LIMIT 1")
    User findByName(String first, String last);

    @Insert
    void insertAll(User... users);

    @Delete
    void delete(User user);
}

AppDataBase

package com.example.demoroom;

import androidx.room.Database;
import androidx.room.RoomDatabase;

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

MainActivity

package com.example.demoroom;

import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

import androidx.appcompat.app.AppCompatActivity;
import androidx.room.Room;

import java.util.List;

public class MainActivity extends AppCompatActivity {

    UserDao uDAO;
    AppDatabase db;
    User u;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        db = Room.databaseBuilder(getApplicationContext(),
                AppDatabase.class, "database-name").build();
        u.firstName = new String("Mike");
        u.lastName = new String("Mathue");
        uDAO = db.getuserDao();
        Log.e("", "onCreate: here");

        ((Button)findViewById(R.id.insert)).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                uDAO.insertAll(u);
                Toast.makeText(MainActivity.this, "刚刚插入信息:firstname:"+u.firstName+"lastname:"+u.lastName, Toast.LENGTH_SHORT).show();
            }
        });

        ((Button)findViewById(R.id.show)).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                List<User> allUsers =  uDAO.getAll();
                StringBuffer message = new StringBuffer("刚刚插入信息:");
                for(int i = 0 ; i < allUsers.size() ; i++) {
                    message.append("firstname-"+i+allUsers.get(i).firstName+"lastname-"+i+allUsers.get(i).lastName);
                }
                Toast.makeText(MainActivity.this, message, Toast.LENGTH_SHORT).show();
            }
        });
    }
}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity"
    android:orientation="horizontal">

    <Button
        android:id="@+id/insert"
        android:text="insert a tuple"
        android:layout_height="wrap_content"
        android:layout_width="match_parent"
        tools:ignore="MissingConstraints" />

    <Button
        android:id="@+id/show"
        android:text="show the first tuple"
        android:layout_height="wrap_content"
        android:layout_width="match_parent"
        tools:ignore="MissingConstraints" />

</LinearLayout>
  • 0
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值