7 خطوات لاستخدام الغرفة. تجول لترحيل طلبك إلى Room

7 خطوات لاستخدام الغرفة. تجول لترحيل طلبك إلى Room


الغرفة عبارة عن مكتبة تشكل جزءًا من المكونات المعمارية لنظام Android. فإنه يسهل العمل مع كائنات SQLiteDatabase في التطبيق ، مما يقلل من كمية التعليمات البرمجية القياسية والتحقق من استعلامات SQL في وقت الترجمة.


هل لديك بالفعل مشروع Android يستخدم SQLite لتخزين البيانات؟ إذا كان الأمر كذلك ، فيمكنك ترحيلها إلى Room. دعونا نرى كيفية اتخاذ مشروع موجود وإعادة تشكيله لاستخدام الغرفة في 7 خطوات بسيطة.


TL ؛ DR: تحديث تبعيات gradle ، إنشاء كياناتك ، DAO وقاعدة البيانات ، واستبدال مكالمات SQLiteDatabase بمكالمات طريقة DAO ، واختبار كل ما قمت بإنشائه أو تعديله ، وحذف الفئات غير المستخدمة. هذا كل شئ!

في نموذج طلبنا للترحيل ، نعمل مع كائنات من النوع User . استخدمنا نكهات المنتج لإظهار العديد من التطبيقات على مستوى البيانات:


  1. sqlite - يستخدم SQLiteOpenHelper واجهات SQLite التقليدية.
  2. room - يستبدل التنفيذ بـ Room ويوفر الترحيل.

يستخدم كل خيار طبقة واجهة المستخدم نفسها ، والتي تعمل مع فئة UserRepository بفضل نمط MVP.


في متغير sqlite ، سترى الكثير من التعليمات البرمجية التي غالباً ما تكون مكررة وتستخدم قاعدة البيانات في UsersDbHelper و LocalUserDataSource . يتم إنشاء الاستعلامات باستخدام ContentValues ، ContentValues البيانات التي يتم إرجاعها بواسطة كائنات Cursor عمودًا تلو الآخر. كل هذا الرمز يساهم في ظهور الأخطاء الضمنية. على سبيل المثال ، يمكنك تخطي إضافة عمود إلى استعلام أو تجميع كائن من قاعدة بيانات بشكل غير صحيح.


دعونا نرى كيف يحسن الغرفة كودنا. في البداية ، نحن ببساطة نسخ الطبقات من البديل sqlite وتغييرها تدريجيا.


الخطوة 1. تحديث تبعيات gradle


تتوفر تبعيات الغرفة من خلال مستودع Google Maven الجديد. فقط أضفه إلى قائمة المستودعات في ملف build.gradle الرئيسي:


 allprojects { repositories { google() jcenter() } } 

تحديد نسخة من مكتبة الغرفة في نفس الملف. أثناء وجوده في إصدار alpha ، لكن ترقب تحديثات الإصدار على صفحات مطور البرامج :


 ext { roomVersion = '2.1.0-alpha03' } 

في app/build.gradle أضف تبعيات لـ Room:


 dependencies { implementation “android.arch.persistence.room:runtime:$rootProject.roomVersion” annotationProcessor “android.arch.persistence.room:compiler:$rootProject.roomVersion” androidTestImplementation “android.arch.persistence.room:testing:$rootProject.roomVersion” } 

للترحيل إلى Room ، نحتاج إلى زيادة إصدار قاعدة البيانات ، وحفظ بيانات المستخدم ، نحتاج إلى تطبيق فئة الترحيل . لاختبار الترحيل ، نحتاج إلى تصدير المخطط. للقيام بذلك ، أضف الكود التالي إلى app/build.gradle :


 android { defaultConfig { ... // used by Room, to test migrations javaCompileOptions { annotationProcessorOptions { arguments = ["room.schemaLocation": "$projectDir/schemas".toString()] } } } // used by Room, to test migrations sourceSets { androidTest.assets.srcDirs += files("$projectDir/schemas".toString()) } ... 

الخطوة 2. تحديث فئات النموذج للكيانات


تنشئ الغرفة جدولًا لكل فئة تحمل علامة Entity . تتوافق الحقول في الفصل مع الأعمدة الموجودة في الجدول. وبالتالي ، فإن فئات الكيانات ، كقاعدة عامة ، هي فئات صغيرة من النماذج التي لا تحتوي على أي منطق. تمثل فئة User نموذجًا للبيانات في قاعدة البيانات. لذلك ، دعونا نقوم بتحديثه لإخبار Room بأنه يجب عليه إنشاء جدول بناءً على هذه الفئة:


  • قم @Entity الفئة مع @Entity واستخدم خاصية tableName لتعيين اسم الجدول.
  • قم بتعيين المفتاح الأساسي عن طريق إضافة تعليق توضيحي @PrimaryKey إلى الحقول الصحيحة - في حالتنا ، هذا هو معرف المستخدم.
  • حدد اسم العمود لحقول الفئة باستخدام التعليق التوضيحي @ColumnInfo(name = "column_name") . يمكنك تخطي هذه الخطوة إذا تم بالفعل تسمية الحقول الخاصة بك كما يجب تسمية العمود.
  • إذا كان هناك العديد من @Ignore في الفصل ، فأضف @Ignore على @Ignore لإخبار Room عن أي منها سيستخدم ولا يجب استخدامه.

 @Entity(tableName = "users") public class User { @PrimaryKey @ColumnInfo(name = "userid") private String mId; @ColumnInfo(name = "username") private String mUserName; @ColumnInfo(name = "last_update") private Date mDate; @Ignore public User(String userName) { mId = UUID.randomUUID().toString(); mUserName = userName; mDate = new Date(System.currentTimeMillis()); } public User(String id, String userName, Date date) { this.mId = id; this.mUserName = userName; this.mDate = date; } ... } 

ملاحظة: @Entity ، @ColumnInfo إلى أسماء الجداول والأعمدة في التطبيق الأصلي وتأكد من تعيينها بشكل صحيح في @ColumnInfo و @ColumnInfo .


الخطوة 3. إنشاء كائنات الوصول إلى البيانات (DAO)


DAOs هي المسؤولة عن تحديد أساليب الوصول إلى قاعدة البيانات. في التنفيذ الأولي لمشروع SQLite لدينا ، تم تنفيذ جميع استعلامات قاعدة البيانات في فئة LocalUserDataSource ، حيث عملنا مع كائنات Cursor . في الغرفة ، لا نحتاج إلى كل الشفرة المرتبطة بالمؤشر ، ويمكننا ببساطة تحديد طلباتنا باستخدام التعليقات التوضيحية في فئة UserDao .


على سبيل المثال ، عند الاستعلام عن جميع المستخدمين من قاعدة البيانات ، يقوم Room بكل "العمل الشاق" ، ونحن بحاجة فقط إلى الكتابة:


 @Query(“SELECT * FROM Users”) List<User> getUsers(); 

الخطوة 4. إنشاء قاعدة بيانات


لقد حددنا بالفعل جدول Users لدينا واستفساراته المقابلة ، لكننا لم نقم بعد بإنشاء قاعدة بيانات توحد جميع مكونات الغرفة هذه. للقيام بذلك ، نحتاج إلى تعريف فئة مجردة يمتد RoomDatabase . هذه الفئة تحمل علامة @Database ، والتي تسرد الكائنات الموجودة في قاعدة البيانات و DAO التي تصل إليها. يجب زيادة نسخة قاعدة البيانات بنسبة 1 مقارنة بالقيمة الأصلية ، لذلك في حالتنا ستكون 2.


 @Database(entities = {User.class}, version = 2) @TypeConverters(DateConverter.class) public abstract class UsersDatabase extends RoomDatabase { private static UsersDatabase INSTANCE; public abstract UserDao userDao(); 

نظرًا لأننا نريد حفظ بيانات المستخدم ، نحتاج إلى تنفيذ غرفة إخبار فئة Migration بما يجب القيام به عند التبديل من الإصدار 1 إلى 2. في حالتنا ، نظرًا لأن مخطط قاعدة البيانات لم يتغير ، فنحن ببساطة نقدم تطبيقًا فارغًا:


 static final Migration MIGRATION_1_2 = new Migration(1, 2) { @Override public void migrate(SupportSQLiteDatabase database) { //     ,      . } }; 

قم بإنشاء كائن قاعدة بيانات في فئة UsersDatabase عن طريق تحديد اسم قاعدة البيانات UsersDatabase :


 database = Room.databaseBuilder(context.getApplicationContext(), UsersDatabase.class, "Sample.db") .addMigrations(MIGRATION_1_2) .build(); 

لمعرفة المزيد حول كيفية تنفيذ ترحيل قاعدة البيانات وكيف تعمل تحت الغطاء ، راجع هذا المنشور .


الخطوة 5. تحديث مستودع لاستخدام الغرفة


لقد أنشأنا قاعدة البيانات الخاصة بنا ، وجدول المستخدم والاستعلامات ، لذلك حان الوقت لاستخدامها. في هذه المرحلة ، سنقوم بتحديث فئة LocalUserDataSource لاستخدام أساليب UserDao . للقيام بذلك ، نقوم أولاً بتحديث المنشئ: قم بإزالة Context وقم بإضافة UserDao . بالطبع ، يجب أيضًا تحديث أي فئة تقوم بإنشاء مثيل لـ LocalUserDataSource .


بعد ذلك ، سنقوم بتحديث أساليب LocalUserDataSource التي تجعل الاستعلامات عن طريق استدعاء أساليب UserDao . على سبيل المثال ، تبدو الطريقة التي تطلب من جميع المستخدمين الآن كما يلي:


 public List<User> getUsers() { return mUserDao.getUsers(); } 

والآن حان الوقت لإطلاق ما فعلناه.


واحدة من أفضل ميزات Room هي أنه إذا أجريت عمليات قاعدة بيانات على سلسلة الرسائل الرئيسية ، فسوف يتعطل التطبيق الخاص بك مع رسالة الخطأ التالية:


 java.lang.IllegalStateException: Cannot access database on the main thread since it may potentially lock the UI for a long period of time. 

إحدى الطرق الموثوقة لنقل عمليات الإدخال / الإخراج من مؤشر الترابط الرئيسي هي إنشاء Runnable جديد من شأنه إنشاء مؤشر ترابط جديد لكل استعلام قاعدة البيانات. نظرًا لأننا نستخدم هذا النهج بالفعل في متغير sqlite ، فلم تكن هناك حاجة للتغييرات.


الخطوة 6. اختبار على الجهاز


أنشأنا فئات جديدة - UserDao و UsersDatabase بتغيير LocalUserDataSource لدينا لاستخدام قاعدة بيانات الغرفة. الآن نحن بحاجة لاختبار لهم.


اختبار UserDao


لاختبار UserDao ، نحتاج إلى إنشاء فئة اختبار AndroidJUnit4 . الميزة المذهلة لـ Room هي القدرة على إنشاء قاعدة بيانات في الذاكرة. هذا يلغي الحاجة إلى التنظيف بعد كل اختبار.


 @Before public void initDb() throws Exception { mDatabase = Room.inMemoryDatabaseBuilder( InstrumentationRegistry.getContext(), UsersDatabase.class) .build(); } 

نحتاج أيضًا إلى التأكد من إغلاق اتصال قاعدة البيانات بعد كل اختبار.


 @After public void closeDb() throws Exception { mDatabase.close(); } 

على سبيل المثال ، لاختبار تسجيل دخول المستخدم ، نضيف مستخدمًا ثم نتحقق مما إذا كان بإمكاننا الحصول على هذا المستخدم من قاعدة البيانات.


 @Test public void insertAndGetUser() { //      mDatabase.userDao().insertUser(USER); //        List<User> users = mDatabase.userDao().getUsers(); assertThat(users.size(), is(1)); User dbUser = users.get(0); assertEquals(dbUser.getId(), USER.getId()); assertEquals(dbUser.getUserName(), USER.getUserName()); } 

اختبار استخدام UserDao في LocalUserDataSource


من السهل التأكد من أن LocalUserDataSource لا يزال يعمل بشكل صحيح ، لأن لدينا بالفعل اختبارات تصف سلوك هذه الفئة. كل ما نحتاج إليه هو إنشاء قاعدة بيانات في الذاكرة ، والحصول على كائن UserDao منه ، واستخدامه كمعلمة LocalUserDataSource .


 @Before public void initDb() throws Exception { mDatabase = Room.inMemoryDatabaseBuilder( InstrumentationRegistry.getContext(), UsersDatabase.class) .build(); mDataSource = new LocalUserDataSource(mDatabase.userDao()); } 

مرة أخرى ، نحتاج إلى التأكد من إغلاق قاعدة البيانات بعد كل اختبار.


اختبار ترحيل قاعدة البيانات


يمكنك قراءة المزيد حول كيفية تطبيق اختبارات ترحيل قاعدة البيانات ، وكذلك كيفية عمل MigrationTestHelper ، في هذا المنشور .


يمكنك أيضًا مشاهدة الرمز من مثال تطبيق الترحيل أكثر تفصيلاً.


الخطوة 7. إزالة جميع لا لزوم لها


قم بإزالة أي فئات وأسطر من التعليمات البرمجية غير المستخدمة يتم استبدالها الآن بوظيفة الغرفة. في مشروعنا ، نحتاج فقط إلى إزالة فئة UsersDbHelper ، التي وسعت فئة SQLiteOpenHelper .


إذا كان لديك قاعدة بيانات أكبر وأكثر تعقيدًا ، وتريد التبديل تدريجياً إلى Room ، فإننا نوصي بهذا المنشور .


الآن انخفض حجم التعليمات البرمجية القياسية المعرضة للخطأ ، ويتم فحص الطلبات في وقت الترجمة ، ويتم اختبار كل شيء. في 7 خطوات بسيطة ، تمكنا من نقل تطبيقنا الحالي إلى Room. يمكنك رؤية تطبيق مثال هنا .

Source: https://habr.com/ru/post/ar441934/


All Articles