Το Room είναι μια βιβλιοθήκη για εργασία με SQLite στο Android, που αποτελεί μέρος του Jetpack. Παρέχει ένα επίπεδο αφαίρεσης πάνω από το ακατέργαστο SQLite, αυτοματοποιώντας τη δημιουργία πινάκων, την εκτέλεση ερωτημάτων και τη μετατροπή δεδομένων σε αντικείμενα Kotlin και Java. Σύμφωνα με το Android Developers, το Room μεταγλωττίζει τα ερωτήματα SQL στο στάδιο κατασκευής, ελέγχοντας την ορθότητα της σύνταξης και των σχέσεων μεταξύ Entity και πινάκων.
Κύρια σημεία
Room — είναι μια βιβλιοθήκη μονιμότητας από το Android Jetpack που παρέχει αντικειμενο-σχεσιακή αντιστοίχιση για SQLite. Το Room λύνει τρία κύρια προβλήματα του ακατέργαστου SQLite: τη συγγραφή μεγάλου όγκου boilerplate κώδικα για τη δημιουργία πινάκων, την έλλειψη ελέγχου ερωτημάτων SQL κατά τη μεταγλώττιση και τη χειροκίνητη μετατροπή Cursor σε αντικείμενα.
Η βιβλιοθήκη χρησιμοποιεί έναν μεταγλωττιστή σχολιασμών (kapt ή KSP) που παράγει την υλοποίηση των αφηρημένων κλάσεων RoomDatabase και DAO στο στάδιο κατασκευής. Αυτό εγγυάται ότι τα συντακτικά λάθη στην SQL και οι αναντιστοιχίες τύπων ανιχνεύονται πριν από την εκκίνηση της εφαρμογής, όχι κατά τον χρόνο εκτέλεσης μετά τη δημοσίευση στο Google Play.
Σύμφωνα με το Google I/O 2023, το Room χρησιμοποιείται στο 68% των εφαρμογών Android που εργάζονται με τοπικά δεδομένα. Είναι το πρότυπο αποθήκευσης δεδομένων στη συσκευή, που προτείνεται από την Google για όλα τα νέα έργα — αντί των παρωχημένων SQLiteOpenHelper και ContentProvider.
Εφαρμόστε το Room σε έργα όπου απαιτείται τοπική προσωρινή αποθήκευση δεδομένων από τον διακομιστή, λειτουργία εκτός σύνδεσης ή αποθήκευση δομημένων δεδομένων χρήστη με δυνατότητα σύνθετων ερωτημάτων SQL.
Το Room είναι μέρος του Android Jetpack και συνιστάται επίσημα από την Google για όλα τα νέα έργα που εργάζονται με τοπικά δεδομένα. Σε αντίθεση με το Realm ή το ObjectBox, το Room χρησιμοποιεί εγγενές SQLite, το οποίο εγγυάται συμβατότητα με οποιαδήποτε εργαλεία τρίτων για εργασία με βάση δεδομένων — από το DB Browser έως το DataGrip. Ο προγραμματιστής μπορεί να ανοίξει το αρχείο .db της εφαρμογής και να εκτελέσει απευθείας ερωτήματα SQL, πράγμα που διευκολύνει τον εντοπισμό σφαλμάτων και την ανάλυση δεδομένων κατά τη διαδικασία ανάπτυξης.
Entity — είναι μια κλάση δεδομένων με σχολιασμό @Entity, την οποία το Room μετατρέπει σε πίνακα βάσης δεδομένων. Κάθε πεδίο της κλάσης γίνεται στήλη του πίνακα και κάθε στιγμιότυπο γίνεται γραμμή. Το Room χρησιμοποιει ανάκλαση για πρόσβαση στα πεδία, επομένως απαιτείται σχολιασμός @PrimaryKey για υποχρεωτικό αναγνωριστικό.
Ο σχολιασμός @Entity ενημερώνει το Room ότι η κλάση είναι ένας πίνακας. Η παράμετρος tableName καθορίζει το όνομα του πίνακα αν διαφέρει από το όνομα της κλάσης. Το @PrimaryKey ορίζει το πρωτεύον κλειδί με δυνατότητα αυτόματης δημιουργίας μέσω autoGenerate = true.
@Entity(tableName = "users")
data class User(
@PrimaryKey(autoGenerate = true)
val id: Int = 0,
@ColumnInfo(name = "full_name")
val name: String,
@Ignore
val tempData: String?
)
@ColumnInfo καθορίζει το όνομα της στήλης στον πίνακα αν διαφέρει από το όνομα πεδίου Kotlin. Το @Ignore εξαιρεί το πεδίο από τον πίνακα — δεν θα αποθηκευτεί στη βάση δεδομένων. Το @ForeignKey περιγράφει ξένα κλειδιά για σχέσεις μεταξύ πινάκων με λειτουργίες αλληλουχίας κατά τη διαγραφή ή ενημέρωση.
Το Room υποστηρίζει ένθετα αντικείμενα μέσω του σχολιασμού @Embedded. Τα πεδία της ένθετης κλάσης αναπτύσσονται σε στήλες του γονικού πίνακα με ένα πρόθεμα για αποφυγή σύγκρουσης ονομάτων. Για παράδειγμα, μια κλάση Address με πεδία city και street, ενσωματωμένη στο User, θα δημιουργήσει τις στήλες address_city και address_street στον πίνακα users, εξαλείφοντας την ανάγκη δημιουργίας ξεχωριστών πινάκων για απλά αντικείμενα τιμών.
Το Room υποστηρίζει μόνο πρωτόγονους τύπους και τα περιτυλίγματά τους. Για αποθήκευση λιστών, Date ή προσαρμοσμένων τύπων χρησιμοποιείται @TypeConverter — στατικές μέθοδοι μετατροπής μεταξύ προσαρμοσμένου τύπου και πρωτόγονου SQLite, για παράδειγμα, μεταξύ List και συμβολοσειράς JSON.
DAO (Data Access Object) — είναι μια διεπαφή ή αφηρημένη κλάση με σχολιασμό @Dao, που περιέχει μεθόδους για πρόσβαση σε δεδομένα. Κάθε μέθοδος σχολιάζεται με μια λειτουργία SQL: @Insert, @Update, @Delete ή @Query με ρητό ερώτημα SQL.
Ο σχολιασμός @Query δέχεται μια συμβολοσειρά SQL που ελέγχεται από το Room κατά τη μεταγλώττιση για ορθότητα σύνταξης και αντιστοιχία ονομάτων στηλών με πεδία Entity. Το Room υποστηρίζει παραμετροποιημένα ερωτήματα μέσω σύνταξης :paramName.
@Dao
interface UserDao {
@Query("SELECT * FROM users WHERE id = :userId")
suspend fun getUserById(userId: Int): User?
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertUser(user: User)
@Query("SELECT * FROM users ORDER BY name ASC")
fun getAllUsers(): Flow<List<User>>
}
@Insert υποστηρίζει στρατηγικές OnConflictStrategy για διαχείριση συγκρούσεων κατά την εισαγωγή διπλότυπων εγγραφών. Flow ως τύπος επιστροφής εξασφαλίζει αντιδραστική ενημέρωση UI σε κάθε αλλαγή δεδομένων στον πίνακα — η συνδρομή επανεκκινείται αυτόματα σε κάθε INSERT, UPDATE ή DELETE.
Ο σχολιασμός @Transaction εγγυάται ατομική εκτέλεση πολλαπλών λειτουργιών σε ένα ενιαίο μπλοκ συναλλαγής. Το Room κλειδώνει τη βάση δεδομένων κατά την εκτέλεση, αποτρέποντας συνθήκες ανταγωνισμού κατά την ταυτόχρονη πρόσβαση από πολλαπλά νήματα.
RoomDatabase — είναι μια αφηρημένη κλάση που ενώνει το Entity και το DAO σε ένα ενιαίο σημείο πρόσβασης στη βάση δεδομένων. Δημιουργείται μέσω Room.databaseBuilder με καθορισμό έκδοσης σχήματος και λίστας κλάσεων Entity. Το στιγμιότυπο της βάσης δεδομένων συνιστάται να δημιουργείται ως singleton μέσω lazy-αντιπροσώπου για αποφυγή πολλαπλών συνδέσεων.
Μετεγκατάσταση στο Room — είναι μια κλάση Migration που περιγράφει ένα σενάριο SQL για μετάβαση από την παλιά έκδοση σχήματος στη νέα. Εάν δεν παρέχεται μετεγκατάσταση κατά την αλλαγή σχήματος, το Room ρίχνει IllegalStateException. Αυτό προστατεύει από τυχαία απώλεια δεδομένων χρήστη κατά την ενημέρωση της εφαρμογής.
val migration_1_2 = object : Migration(1, 2) {
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL("ALTER TABLE users ADD COLUMN age INTEGER NOT NULL DEFAULT 0")
}
}
val db = Room.databaseBuilder(
getApplication(),
AppDatabase::class.java,
"app_database"
).addMigrations(migration_1_2)
.build()
Για ανάπτυξη μπορεί να χρησιμοποιηθεί fallbackToDestructiveMigration, το οποίο διαγράφει την παλιά βάση και δημιουργεί νέα όταν οι εκδόσεις δεν ταιριάζουν. Αυτή η λειτουργία προορίζεται μόνο για εντοπισμό σφαλμάτων — σε εκδόσεις παραγωγής γράφονται υποχρεωτικά μετεγκαταστάσεις.
Για δοκιμή της βάσης δεδομένων, το Room παρέχει μια ειδική κλάση Room.inMemoryTestBuilder, η οποία δημιουργεί βάση δεδομένων στη μνήμη RAM χωρίς αποθήκευση στο δίσκο. Μετά την ολοκλήρωση κάθε δοκιμής, η βάση καταστρέφεται αυτόματα, εγγυώμενη πλήρη απομόνωση των σεναρίων δοκιμής. Σε συνδυασμό με τη βιβλιοθήκη android-arch-core-testing, ο προγραμματιστής μπορεί να διαχειριστεί τον κύκλο ζωής της βάσης και να ελέγξει την ορθότητα των μετεγκαταστάσεων χωρίς να χρειάζεται να καθαρίσει χειροκίνητα την κατάσταση.
Η απόδοση του Room εξαρτάται άμεσα από τη δομή των ερωτημάτων και των ευρετηρίων. Για ανάλυση αργών ερωτημάτων, το Room παρέχει τη σημαία enableQueryCallback, η οποία καταγράφει όλα τα ερωτήματα SQL με τον χρόνο εκτέλεσης. Ο προγραμματιστής μπορεί να χρησιμοποιήσει αυτό το αρχείο καταγραφής για να βρει ερωτήματα που διαρκούν περισσότερο από 100 χιλιοστά του δευτερολέπτου και να τα βελτιστοποιήσει προσθέτοντας σύνθετα ευρετήρια μέσω του σχολιασμού @Index στο @Entity ή ξαναγράφοντας υποερωτήματα σε άμεσες συνδέσεις JOIN χρησιμοποιώντας @Relation.
Το Room υποστηρίζει επίσης κρυπτογράφηση βάσης δεδομένων μέσω SQLCipher. Η σύνδεση της βιβλιοθήκης net.zetetic:android-database-sqlcipher και η χρήση SupportFactory αντί της τυπικής εξασφαλίζει διαφανή κρυπτογράφηση όλων των δεδομένων στο δίσκο χωρίς αλλαγή των ερωτημάτων DAO και της δομής Entity. Αυτό είναι απαραίτητο για εφαρμογές που εργάζονται με προσωπικά δεδομένα χρηστών και πληροί τις απαιτήσεις GDPR και του ρωσικού νόμου 152-ΦΖ για την προστασία προσωπικών δεδομένων. Ο κωδικός πρόσβασης κρυπτογράφησης μπορεί να αποθηκευτεί στο Android Keystore για προστασία από εξαγωγή μέσω εργαλείων σε συσκευές με δικαιώματα root.
Room υποστηρίζει εγγενώς τα Kotlin Coroutines από την έκδοση 2.1. Οι μέθοδοι DAO μπορούν να είναι συναρτήσεις suspend που εκτελούν ερωτήματα στο παρασκήνιο χωρίς να μπλοκάρουν το κύριο νήμα. Το Room διαχειρίζεται αυτόματα τους διανομείς, χρησιμοποιώντας Dispatchers.IO για ερωτήματα ανάγνωσης και εγγραφής.
Για αντιδραστικά ερωτήματα, το Room επιστρέφει Flow — μια ψυχρή ροή δεδομένων που εκπέμπει μια νέα τιμή σε κάθε αλλαγή του επηρεαζόμενου πίνακα. Το ViewModel εγγράφεται στο Flow μέσω stateIn ή collect, εξασφαλίζοντας αυτόματη ενημέρωση UI χωρίς χειροκίνητη ειδοποίηση του προσαρμογέα.
Το Room υποστηρίζει επίσης Paging 3 μέσω μιας ειδικής υλοποίησης PagingSource που φορτώνει δεδομένα σε σελίδες από το SQLite. Αυτό είναι αποτελεσματικό για μεγάλες λίστες με χιλιάδες εγγραφές: το Paging 3 φορτώνει μόνο τις ορατές γραμμές στην οθόνη και τις ενημερώνει αυτόματα σε αλλαγές στη βάση δεδομένων.
Χρησιμοποιήστε το Paging 3 με το Room κατά την εμφάνιση ροής ειδήσεων, αρχείου καταγραφής λειτουργιών ή λίστας προϊόντων με δυνατότητα πρόσβασης εκτός σύνδεσης και ατέρμονης κύλισης.
Συχνές Ερωτήσεις
Room αυτοματοποιεί τη δημιουργία πινάκων, τη μετατροπή Cursor σε αντικείμενα και τον έλεγχο SQL κατά τη μεταγλώττιση. Το SQLiteOpenHelper απαιτεί χειροκίνητη συγγραφή σχήματος, επεξεργασία Cursor και δεν έχει έλεγχο ερωτημάτων πριν από την εκκίνηση της εφαρμογής, αυξάνοντας τον κίνδυνο σφαλμάτων.
Ναι, κατά την αλλαγή Entity (προσθήκη/αφαίρεση πεδίου, αλλαγή τύπου) απαιτείται μετεγκατάσταση. Χωρίς αυτήν, το Room ρίχνει IllegalStateException κατά την εκκίνηση. Για ανάπτυξη μπορεί να ενεργοποιηθεί το fallbackToDestructiveMigration, αλλά στην έκδοση είναι υποχρεωτικά σωστά σενάρια μετεγκατάστασης.
Το Room υποστηρίζει @ForeignKey για λειτουργίες αλληλουχίας και @Relation για ένθετα αντικείμενα. Για σύνθετα ερωτήματα JOIN χρησιμοποιείται ο σχολιασμός @Transaction με @Query που επιστρέφει POJO με ένθετες οντότητες μέσω @Embedded και @Relation.
Ναι, το Room είναι πλήρως συμβατό με Java. Αντί για συναρτήσεις suspend χρησιμοποιούνται LiveData ή RxJava Observable, αντί για Flow — LiveData. Το Room με Java υποστηρίζει όλους τους ίδιους σχολιασμούς, αλλά απαιτεί περισσότερο boilerplate κώδικα για ασύγχρονες λειτουργίες.
Το Room υποστηρίζει κρυπτογράφηση μέσω SQLCipher από τη Zetetic. Αντί για Room.databaseBuilder χρησιμοποιήστε SupportFactory από τη βιβλιοθήκη net.zetetic:android-database-sqlcipher, μεταβιβάζοντας τον κωδικό πρόσβασης κρυπτογράφησης. Όλα τα δεδομένα στο δίσκο θα κρυπτογραφηθούν διαφανώς για τα ερωτήματα DAO.
Σύνοψη
Θα αναπτύξουμε μια εφαρμογή για κινητά έτοιμη για χρήση
Η IT Sectr δημιουργεί εφαρμογές iOS και Android για νεοφυείς επιχειρήσεις και επιχειρήσεις από το 2017. Θα σας συμβουλεύσουμε και θα προτείνουμε την καλύτερη λύση.
Διαβάστε επίσης