当转换器类没有实现任何接口时,Room 如何知道如何使用自定义 TypeConverter?

问题描述 投票:0回答:1

这是我们使用 Room 库创建数据库的方式:

database = Room.databaseBuilder(
        this,
        WordInfoDatabase::class.java,
        "word_db"
    ).addTypeConverter(Converters(GsonParser(Gson())))
        .build()

我们可以通过方法

addTypeConverter(typeConverter: Any)
指定我们想要使用的自定义转换器。 typeConverter 类的方法可以具有从 toJsonfromJsonqwerty 的任何名称,它们还可以采用不同的数据类型作为参数并返回不同的数据类型作为结果,例如

 @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 如何知道如何正确使用它们?

android android-room typeconverter
1个回答
0
投票

当您编译项目时,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
带注释的抽象类

  1. 前面是 @TypeConverters 注释(TypeConverters 的最完整范围)
  2. 包括相应的
    @Entity
    带注释的类
  3. 有一个检索
    @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();
  }
}
  • 显然提供的类型转换器有点不同
© www.soinside.com 2019 - 2024. All rights reserved.