Auf komplexe Daten mit Room verweisen

Der Chatroom bietet Funktionen zum Konvertieren zwischen primitiven und eingerahmten Typen Objektverweise zwischen Entitäten sind jedoch nicht zulässig. Dieses Dokument erklärt, wie Typkonverter verwendet werden und warum Room keine Objekte unterstützt Referenzen.

Typkonverter verwenden

Manchmal muss Ihre Anwendung einen benutzerdefinierten Datentyp in einer einzigen Datenbank speichern Spalte. Sie unterstützen benutzerdefinierte Typen, indem Sie Typkonverter angeben. Dies sind , die Room mitteilen, wie benutzerdefinierte Typen in und aus bekannten Typen konvertiert werden sollen, Der Chatroom kann bestehen bleiben. Sie identifizieren Typkonverter mithilfe der Methode @TypeConverter-Anmerkung.

Angenommen, Sie müssen Instanzen von Date in in Ihrer Raumdatenbank. Der Raum weiß nicht, wie Date-Objekte persistiert werden, daher benötigen Sie zur Definition von Typkonvertern:

Kotlin

class Converters {
  @TypeConverter
  fun fromTimestamp(value: Long?): Date? {
    return value?.let { Date(it) }
  }

  @TypeConverter
  fun dateToTimestamp(date: Date?): Long? {
    return date?.time?.toLong()
  }
}

Java

public class Converters {
  @TypeConverter
  public static Date fromTimestamp(Long value) {
    return value == null ? null : new Date(value);
  }

  @TypeConverter
  public static Long dateToTimestamp(Date date) {
    return date == null ? null : date.getTime();
  }
}

In diesem Beispiel werden zwei Methoden zum Typkonverter definiert: eine, die einen Date konvertiert. in ein Long-Objekt und eines, das die umgekehrte Konvertierung von Long bis Date. Da Room Long-Objekte persistieren kann, kann es diese Converter so, dass sie Date-Objekte beibehalten.

Als Nächstes fügen Sie den @TypeConverters hinzu. an die AppDatabase-Klasse an, damit Room Informationen zum Konverter erhalten. von Ihnen definierter Klasse:

Kotlin

@Database(entities = [User::class], version = 1)
@TypeConverters(Converters::class)
abstract class AppDatabase : RoomDatabase() {
  abstract fun userDao(): UserDao
}

Java

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

Wenn diese Typkonverter definiert sind, können Sie Ihren benutzerdefinierten Typ in Ihrem Entitäten und DAOs genau wie primitive Typen verwenden:

Kotlin

@Entity
data class User(private val birthday: Date?)

@Dao
interface UserDao {
  @Query("SELECT * FROM user WHERE birthday = :targetDate")
  fun findUsersBornOnDate(targetDate: Date): List<User>
}

Java

@Entity
public class User {
  private Date birthday;
}

@Dao
public interface UserDao {
  @Query("SELECT * FROM user WHERE birthday = :targetDate")
  List<User> findUsersBornOnDate(Date targetDate);
}

In diesem Beispiel kann der definierte Typkonverter überall verwendet werden, hat AppDatabase mit @TypeConverters kommentiert. Sie können jedoch auch den Bereich Nutzer, die eine Conversion zu bestimmten Entitäten oder DAOs ausführen, durch Anmerkungen zu @Entity oder @Dao Klassen mit @TypeConverters.

Initialisierung des Steuerelementtypkonverters

Normalerweise übernimmt Room die Instanziierung von Typkonvertern für Sie. Sie können jedoch Manchmal müssen Sie möglicherweise zusätzliche Abhängigkeiten an Ihren Typkonverter übergeben. -Klassen, was bedeutet, dass Ihre App die Initialisierung direkt steuern muss. Ihrer Typkonverter ein. Annotieren Sie in diesem Fall Ihre Konverterklasse mit @ProvidedTypeConverter:

Kotlin

@ProvidedTypeConverter
class ExampleConverter {
  @TypeConverter
  fun StringToExample(string: String?): ExampleType? {
    ...
  }

  @TypeConverter
  fun ExampleToString(example: ExampleType?): String? {
    ...
  }
}

Java

@ProvidedTypeConverter
public class ExampleConverter {
  @TypeConverter
  public Example StringToExample(String string) {
    ...
  }

  @TypeConverter
  public String ExampleToString(Example example) {
    ...
  }
}

Verwenden Sie dann neben der Deklaration der Konverterklasse in @TypeConverters Folgendes: die RoomDatabase.Builder.addTypeConverter() Methode zur Übergabe einer Instanz der Konverterklasse an die RoomDatabase Builder:

Kotlin

val db = Room.databaseBuilder(...)
  .addTypeConverter(exampleConverterInstance)
  .build()

Java

AppDatabase db = Room.databaseBuilder(...)
  .addTypeConverter(exampleConverterInstance)
  .build();

Warum sind in „Room“ keine Objektverweise zulässig?

Wichtigste Erkenntnis: In diesem Chatroom sind Objektverweise zwischen Entitätsklassen nicht zulässig. Stattdessen müssen Sie explizit die Daten anfordern, die Ihre App benötigt.

Die Zuordnung von Beziehungen aus einer Datenbank zum jeweiligen Objektmodell ist eine gängige und funktioniert auf Server-Seite sehr gut. Auch wenn das Programm wenn darauf zugegriffen wird, funktioniert der Server dennoch gut.

Clientseitig ist diese Art von Lazy Loading jedoch nicht möglich, Sie erfolgt normalerweise im UI-Thread und die Abfrage von Informationen auf dem Laufwerk in der Benutzeroberfläche führt zu erheblichen Leistungsproblemen. Der UI-Thread enthält normalerweise etwa 16 ms, um das aktualisierte Layout einer Aktivität zu berechnen und zu zeichnen. nur 5 ms dauert, ist es trotzdem wahrscheinlich, dass Ihre App den Rahmen zeichnen, was zu wahrnehmbaren optischen Störungen führt. Die Abfrage könnte sogar noch mehr Zeit für den Abschluss, wenn eine separate Transaktion parallel läuft, oder Auf dem Gerät werden andere datenintensive Aufgaben ausgeführt. Wenn Sie keine ruft Ihre App jedoch mehr Daten ab, als sie benötigt, Konsumprobleme.

Objektrelationale Zuordnungen überlassen diese Entscheidung in der Regel den Entwickelnden, damit was für die Anwendungsfälle ihrer App am besten ist. Entwickler in der Regel das Modell zwischen der App und der Benutzeroberfläche zu teilen. Diese Lösung Das Modell lässt sich gut skalieren. Da sich die Benutzeroberfläche im Laufe der Zeit ändert, schafft Probleme, die für Entwickelnde schwer vorhersehbar und schwer zu beheben sind.

Stellen Sie sich beispielsweise eine Benutzeroberfläche vor, über die eine Liste von Book-Objekten mit jedem Buch geladen wird. mit einem Author-Objekt. Sie könnten Ihre Abfragen anfangs wird geladen, damit Instanzen von Book den Autor abrufen. Der erste Abruf von Das Feld author fragt die Datenbank ab. Etwas später stellen Sie fest, den Namen des Autors auch auf der Benutzeroberfläche Ihrer App anzeigen. Sie können auf diese wie im folgenden Code-Snippet gezeigt:

Kotlin

authorNameTextView.text = book.author.name

Java

authorNameTextView.setText(book.getAuthor().getName());

Diese scheinbar harmlose Änderung führt jedoch dazu, dass die Tabelle Author abgefragt wird im Hauptthread.

Wenn Sie die Autoreninformationen vorzeitig abfragen, wird es schwierig, wie Daten geladen werden, wenn Sie sie nicht mehr benötigen. Wenn die App beispielsweise Die Benutzeroberfläche muss keine Informationen zu Author mehr anzeigen, deine App wird effektiv geladen die nicht mehr angezeigt werden, wodurch wertvollen Speicherplatz verschwendet wird. Der Die Effizienz verschlechtert sich noch weiter, wenn die Klasse Author auf eine andere Tabelle verweist. z. B. Books.

Wenn Sie in einem Chatroom auf mehrere Elemente gleichzeitig verweisen möchten, erstellen Sie stattdessen einen POJO, der alle Entitäten enthält, und schreiben Sie dann eine Abfrage, die die entsprechenden Tabellen. Dieses gut strukturierte Modell kombiniert mit der robusten Abfrage von Room Validierungsfunktionen, mit denen Ihre Anwendung beim Laden weniger Ressourcen verbraucht und so die Leistung und Nutzerfreundlichkeit Ihrer App verbessern.