这是我们使用 Room 库创建数据库的方式:
database = Room.databaseBuilder(
this,
WordInfoDatabase::class.java,
"word_db"
).addTypeConverter(Converters(GsonParser(Gson())))
.build()
我们可以通过方法
addTypeConverter(typeConverter: Any)
指定我们想要使用的自定义转换器。 typeConverter 类的方法可以具有从 toJson 或 fromJson 到 qwerty 的任何名称,它们还可以采用不同的数据类型作为参数并返回不同的数据类型作为结果,例如
@TypeConverter
fun instantToLong(timestamp: Instant?) = timestamp?.toEpochMilli()
@TypeConverter
fun longToInstant(timestamp: Long?) =
timestamp?.let { Instant.ofEpochMilli(it) }
或
@ProvidedTypeConverter
class Converters(
private val jsonParser: JsonParser
) {
@TypeConverter
fun fromMeaningsJson(json: String): List<Meaning> {
return jsonParser.fromJson<ArrayList<Meaning>>(
json,
object : TypeToken<ArrayList<Meaning>>(){}.type
) ?: emptyList()
}
@TypeConverter
fun toMeaningsJson(meanings: List<Meaning>): String {
return jsonParser.toJson(
meanings,
object : TypeToken<ArrayList<Meaning>>(){}.type
) ?: "[]"
}
}
那么 Room 如何知道如何正确使用它们?
当您编译项目时,Room 注释会根据 room 编译器注释处理器生成底层 java 代码。
通过
@Database
注解的类的函数/方法和 @Dao
注解的函数调用底层 Java。
考虑代码的简化版本,其中包含一些假定的附加类:-
首先是一个Meaning类(将被转换):-
data class Meaning(
val col1: String,
val col2: String
)
以及
Converters类中的 Meaning 类的一对关联的
TypeConverter
函数(相应注释):-
class Converters {
@TypeConverter
fun fromMeaningsJson(json: String): Meaning = Gson().fromJson(json,Meaning::class.java)
@TypeConverter
fun toMeaningsJson(meaning: Meaning): String = Gson().toJson(meaning)
}
@Entity
,表的类,在需要类型转换的列中具有Meaning:-
@实体 数据类表1( @首要的关键 val id: Long?=null, val m1:含义 )
带有 2 个函数(插入和提取)的
@Dao
带注释的接口,需要进行类型转换
@Dao
interface AllDAOs {
@Insert
fun insert(table1: Table1): Long
@Query("SELECT * FROM table1")
fun getALlTable1Row(): List<Table1>
}
最后一个
@Database
带注释的抽象类
@Entity
带注释的类@Dao
接口的功能(所以它们被包含在内):-
@TypeConverters(Converters::class)
@Database(entities = [Table1::class], version = 1, exportSchema = false)
abstract class TheDatabase: RoomDatabase() {
abstract fun getAllDAOs(): AllDAOs
}
编译上述内容后(通过 Android 视图):-
可以看出有两个相关的java类。一个用于
@Dao
带注释的接口(如果更多 @Dao
带注释的接口,则更多)具有相同的名称,但后缀为 _Impl。另一个同样适用于 @Database
带注释的类(更多 @Database
带注释的类),同样以 _Impl 为后缀。
它来自 AllDAO_Impl 类,您可以在其中看到如何实现/调用 TypeConverter 函数:-
@SuppressWarnings({"unchecked", "deprecation"})
public final class AllDAOs_Impl implements AllDAOs {
private final RoomDatabase __db;
private final EntityInsertionAdapter<Table1> __insertionAdapterOfTable1;
private final Converters __converters = new Converters();
public AllDAOs_Impl(@NonNull final RoomDatabase __db) {
this.__db = __db;
this.__insertionAdapterOfTable1 = new EntityInsertionAdapter<Table1>(__db) {
@Override
@NonNull
protected String createQuery() {
return "INSERT OR ABORT INTO `Table1` (`id`,`m1`) VALUES (?,?)";
}
@Override
protected void bind(@NonNull final SupportSQLiteStatement statement,
@NonNull final Table1 entity) {
if (entity.getId() == null) {
statement.bindNull(1);
} else {
statement.bindLong(1, entity.getId());
}
final String _tmp = __converters.toMeaningsJson(entity.getM1());
if (_tmp == null) {
statement.bindNull(2);
} else {
statement.bindString(2, _tmp);
}
}
};
}
@Override
public long insert(final Table1 table1) {
__db.assertNotSuspendingTransaction();
__db.beginTransaction();
try {
final long _result = __insertionAdapterOfTable1.insertAndReturnId(table1);
__db.setTransactionSuccessful();
return _result;
} finally {
__db.endTransaction();
}
}
@Override
public List<Table1> getALlTable1Row() {
final String _sql = "SELECT * FROM table1";
final RoomSQLiteQuery _statement = RoomSQLiteQuery.acquire(_sql, 0);
__db.assertNotSuspendingTransaction();
final Cursor _cursor = DBUtil.query(__db, _statement, false, null);
try {
final int _cursorIndexOfId = CursorUtil.getColumnIndexOrThrow(_cursor, "id");
final int _cursorIndexOfM1 = CursorUtil.getColumnIndexOrThrow(_cursor, "m1");
final List<Table1> _result = new ArrayList<Table1>(_cursor.getCount());
while (_cursor.moveToNext()) {
final Table1 _item;
final Long _tmpId;
if (_cursor.isNull(_cursorIndexOfId)) {
_tmpId = null;
} else {
_tmpId = _cursor.getLong(_cursorIndexOfId);
}
final Meaning _tmpM1;
final String _tmp;
if (_cursor.isNull(_cursorIndexOfM1)) {
_tmp = null;
} else {
_tmp = _cursor.getString(_cursorIndexOfM1);
}
_tmpM1 = __converters.fromMeaningsJson(_tmp);
_item = new Table1(_tmpId,_tmpM1);
_result.add(_item);
}
return _result;
} finally {
_cursor.close();
_statement.release();
}
}
@NonNull
public static List<Class<?>> getRequiredConverters() {
return Collections.emptyList();
}
}