این کد لبه بخشی از دوره آموزشی Android Kotlin Fundamentals است. اگر به ترتیب روی کدها کار کنید، بیشترین ارزش را از این دوره خواهید گرفت. همه کد لبه های دوره در صفحه فرود کد لبه های Android Kotlin Fundamentals فهرست شده اند.
مقدمه
بیشتر برنامهها دادههایی دارند که حتی پس از بستن برنامه توسط کاربر، باید حفظ شوند. برای مثال، برنامه ممکن است فهرست پخش، فهرستی از اقلام بازی، سوابق هزینهها و درآمد، فهرستی از صورتهای فلکی، یا دادههای خواب را در طول زمان ذخیره کند. معمولاً از یک پایگاه داده برای ذخیره داده های پایدار استفاده می کنید.
Room یک کتابخانه پایگاه داده است که بخشی از Android Jetpack است. Room بسیاری از کارهای راه اندازی و پیکربندی یک پایگاه داده را بر عهده می گیرد و این امکان را برای برنامه شما فراهم می کند تا با استفاده از فراخوانی های تابع معمولی با پایگاه داده تعامل داشته باشد. در زیر هود، Room یک لایه انتزاعی در بالای پایگاه داده SQLite است. اصطلاحات Room ، و نحو پرس و جو برای پرس و جوهای پیچیده تر، از مدل SQLite پیروی می کنند.
تصویر زیر نشان می دهد که چگونه پایگاه داده Room با معماری کلی توصیه شده در این دوره مطابقت دارد.

آنچه از قبل باید بدانید
شما باید با این موارد آشنا باشید:
- ساخت یک رابط کاربری اولیه (UI) برای یک برنامه اندروید
- استفاده از فعالیت ها، قطعات و نماها.
- پیمایش بین قطعات و استفاده از Safe Args (یک افزونه Gradle) برای انتقال داده ها بین قطعات.
- مدلها، کارخانههای مشاهده مدل، و
LiveDataو ناظران آن را مشاهده کنید. این مباحث مولفه های معماری در یک کدآلب قبلی در این دوره پوشش داده شده است. - درک اولیه از پایگاه داده SQL و زبان SQLite. برای یک مرور کلی یا تازهسازی به SQLite Primer مراجعه کنید.
چیزی که یاد خواهید گرفت
- نحوه ایجاد و تعامل با پایگاه داده
Roomبرای ماندگاری داده ها. - نحوه ایجاد یک کلاس داده که یک جدول را در پایگاه داده تعریف می کند.
- نحوه استفاده از یک شی دسترسی به داده (DAO) برای نگاشت توابع Kotlin به پرس و جوهای SQL.
- چگونه آزمایش کنیم که آیا پایگاه داده شما کار می کند یا خیر.
کاری که خواهی کرد
- یک پایگاه داده
Roomبا یک رابط برای داده های خواب شبانه ایجاد کنید. - پایگاه داده را با استفاده از تست های ارائه شده تست کنید.
در این نرم افزار کد، بخش پایگاه داده یک برنامه را می سازید که کیفیت خواب را ردیابی می کند. این برنامه از یک پایگاه داده برای ذخیره داده های خواب در طول زمان استفاده می کند.
این برنامه دارای دو صفحه است که با قطعات نشان داده شده است، همانطور که در شکل زیر نشان داده شده است.
اولین صفحه نمایش داده شده در سمت چپ دارای دکمه هایی برای شروع و توقف ردیابی است. صفحه نمایش تمام داده های خواب کاربر را نشان می دهد. دکمه Clear تمام داده هایی را که برنامه برای کاربر جمع آوری کرده است برای همیشه حذف می کند.
صفحه دوم، نشان داده شده در سمت راست، برای انتخاب رتبه بندی کیفیت خواب است. در برنامه، امتیاز به صورت عددی نشان داده می شود. برای اهداف توسعه، برنامه هم نمادهای چهره و هم معادل های عددی آنها را نشان می دهد.
جریان کاربر به شرح زیر است:
- کاربر برنامه را باز می کند و با صفحه ردیابی خواب نمایش داده می شود.
- کاربر روی دکمه Start ضربه می زند. این زمان شروع را ثبت کرده و نمایش می دهد. دکمه Start غیرفعال است و دکمه Stop فعال است.
- کاربر روی دکمه Stop ضربه می زند. این کار زمان پایان را ثبت می کند و صفحه با کیفیت خواب را باز می کند.
- کاربر یک نماد کیفیت خواب را انتخاب می کند. صفحه بسته می شود و صفحه ردیابی زمان پایان خواب و کیفیت خواب را نشان می دهد. دکمه Stop غیرفعال و دکمه Start فعال است. برنامه برای یک شب دیگر آماده است.
- دکمه Clear هر زمان که داده ای در پایگاه داده وجود داشته باشد فعال می شود. هنگامی که کاربر روی دکمه Clear ضربه میزند، تمام دادههای او بدون مراجعه پاک میشوند - "آیا مطمئن هستید؟" وجود ندارد. پیام
این برنامه از معماری ساده شده استفاده می کند، همانطور که در زیر در زمینه معماری کامل نشان داده شده است. این برنامه فقط از اجزای زیر استفاده می کند:
- کنترلر رابط کاربری
- مشاهده مدل و
LiveData - پایگاه داده اتاق
مرحله 1: برنامه شروع را دانلود و اجرا کنید
- برنامه TrackMySleepQuality-Starter را از GitHub دانلود کنید.
- برنامه را بسازید و اجرا کنید. برنامه رابط کاربری بخش
SleepTrackerFragmentرا نشان می دهد، اما داده ای ندارد. دکمه ها به ضربه ها پاسخ نمی دهند.
مرحله 2: برنامه شروع را بررسی کنید
- به فایل های Gradle نگاهی بیندازید:
- فایل پروژه Gradle
در فایلbuild.gradleدر سطح پروژه، به متغیرهایی که نسخه های کتابخانه را مشخص می کنند توجه کنید. نسخه های استفاده شده در برنامه استارتر به خوبی با هم کار می کنند و با این برنامه به خوبی کار می کنند. تا زمانی که این کد لبه را تمام کنید، ممکن است Android Studio از شما بخواهد که برخی از نسخه ها را به روز کنید. این به شما بستگی دارد که آیا می خواهید نسخه های موجود در برنامه را به روز کنید یا از آن استفاده کنید. اگر با خطاهای کامپایل "عجیب" مواجه شدید، سعی کنید از ترکیب نسخه های کتابخانه ای که برنامه راه حل نهایی استفاده می کند استفاده کنید. - فایل ماژول Gradle. به وابستگیهای ارائهشده برای همه کتابخانههای Android Jetpack، از جمله
Room، و وابستگیهای کوروتینها توجه کنید.
- به بسته ها و UI نگاهی بیندازید. برنامه بر اساس عملکرد ساختار یافته است. این بسته حاوی فایلهای نگهدارنده است که در آن کد را در این سری از کدها اضافه خواهید کرد.
- بسته
database، برای همه کدهای مربوط به پایگاه دادهRoom. - بستههای
sleepqualityوsleeptrackerشامل قطعه، مدل view و کارخانه مدل view برای هر صفحه هستند .
- به فایل
Util.ktنگاهی بیندازید، که حاوی توابعی برای کمک به نمایش داده های با کیفیت خواب است. برخی از کدها به دلیل ارجاع به یک مدل view که بعداً ایجاد می کنید، توضیح داده می شود. - به پوشه androidTest (
SleepDatabaseTest.kt) نگاهی بیندازید. شما از این تست برای بررسی اینکه پایگاه داده طبق برنامه کار می کند استفاده خواهید کرد.
در اندروید، دادهها در کلاسهای داده نمایش داده میشوند و دادهها با استفاده از فراخوانی تابع قابل دسترسی و تغییر هستند. با این حال، در دنیای پایگاه داده، شما به نهادها و پرس و جو نیاز دارید.
- یک موجودیت یک شی یا مفهوم و خصوصیات آن را برای ذخیره در پایگاه داده نشان می دهد. یک کلاس موجودیت یک جدول را تعریف می کند و هر نمونه از آن کلاس نشان دهنده یک ردیف در جدول است. هر ویژگی یک ستون را تعریف می کند. در برنامه شما، نهاد اطلاعاتی در مورد یک شب خواب نگه می دارد.
- پرس و جو درخواست داده یا اطلاعات از جدول پایگاه داده یا ترکیبی از جداول یا درخواستی برای انجام عملی بر روی داده است. پرس و جوهای رایج برای دریافت، درج و به روز رسانی موجودیت ها هستند. برای مثال، میتوانید برای تمام شبهای خواب ثبت شده، مرتبسازیشده بر اساس زمان شروع، پرس و جو کنید.
Room همه کار سختی را برای شما انجام می دهد تا از کلاس های داده Kotlin به موجودیت هایی که می توانند در جداول SQLite ذخیره شوند و از اعلان های تابع تا پرس و جوهای SQL را به دست آورید.
شما باید هر موجودیت را به عنوان یک کلاس داده مشروح، و تعاملات را به عنوان یک رابط مشروح شده، یک شی دسترسی به داده (DAO) تعریف کنید. Room از این کلاس های حاشیه نویسی برای ایجاد جداول در پایگاه داده و پرس و جوهایی که روی پایگاه داده عمل می کنند استفاده می کند.

مرحله 1: موجودیت SleepNight را ایجاد کنید
در این کار، یک شب خواب را به عنوان یک کلاس داده مشروح تعریف می کنید.
برای یک شب خواب، باید زمان شروع، زمان پایان و رتبه بندی کیفیت را ثبت کنید.
و برای شناسایی منحصر به فرد شب به یک شناسه نیاز دارید.
- در بسته
database، فایلSleepNight.ktرا پیدا کرده و باز کنید. - کلاس داده
SleepNightرا با پارامترهایی برای شناسه، زمان شروع (بر حسب میلی ثانیه)، زمان پایان (بر حسب میلی ثانیه) و رتبه بندی عددی کیفیت خواب ایجاد کنید.
- شما باید
sleepQualityرا مقداردهی اولیه کنید، بنابراین آن را روی-1تنظیم کنید، که نشان می دهد هیچ داده با کیفیتی جمع آوری نشده است. - شما همچنین باید زمان پایان را مقداردهی اولیه کنید. آن را روی زمان شروع تنظیم کنید تا نشان دهد که هنوز زمان پایانی ثبت نشده است.
data class SleepNight(
var nightId: Long = 0L,
val startTimeMilli: Long = System.currentTimeMillis(),
var endTimeMilli: Long = startTimeMilli,
var sleepQuality: Int = -1
)- قبل از اعلان کلاس، کلاس داده را با
@Entityحاشیه نویسی کنید. نام جدول راdaily_sleep_quality_tableبگذارید. آرگومانtableNameاختیاری است، اما توصیه می شود. می توانید سایر استدلال ها را در مستندات جستجو کنید.
در صورت درخواست،Entityو تمام حاشیه نویسی های دیگر را از کتابخانهandroidxوارد کنید.
@Entity(tableName = "daily_sleep_quality_table")
data class SleepNight(...)- برای شناسایی
nightIdبه عنوان کلید اصلی، ویژگیnightIdرا با@PrimaryKeyحاشیه نویسی کنید. پارامترautoGenerateرویtrueتنظیم کنید تاRoomبرای هر موجودیت شناسه تولید کند. این تضمین می کند که شناسه هر شب منحصر به فرد است.
@PrimaryKey(autoGenerate = true)
var nightId: Long = 0L,...- ویژگی های باقی مانده را با
@ColumnInfoحاشیه نویسی کنید. مطابق شکل زیر نام ویژگی ها را با استفاده از پارامترها سفارشی کنید.
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
@Entity(tableName = "daily_sleep_quality_table")
data class SleepNight(
@PrimaryKey(autoGenerate = true)
var nightId: Long = 0L,
@ColumnInfo(name = "start_time_milli")
val startTimeMilli: Long = System.currentTimeMillis(),
@ColumnInfo(name = "end_time_milli")
var endTimeMilli: Long = startTimeMilli,
@ColumnInfo(name = "quality_rating")
var sleepQuality: Int = -1
)- کد خود را بسازید و اجرا کنید تا مطمئن شوید که هیچ خطایی ندارد.
در این کار، یک شی دسترسی به داده (DAO) را تعریف می کنید. در اندروید، DAO روشهای آسانی را برای درج، حذف و بهروزرسانی پایگاه داده ارائه میکند.
هنگامی که از پایگاه داده Room استفاده می کنید، با تعریف و فراخوانی توابع Kotlin در کد خود، پایگاه داده را پرس و جو می کنید. این توابع Kotlin به پرس و جوهای SQL نگاشت می شوند. شما آن نگاشتها را در یک DAO با استفاده از حاشیه نویسی تعریف می کنید و Room کد لازم را ایجاد می کند.
یک DAO را به عنوان تعریف یک رابط سفارشی برای دسترسی به پایگاه داده خود در نظر بگیرید.
برای عملیات رایج پایگاه داده، کتابخانه Room حاشیه نویسی های راحت را ارائه می دهد، مانند @Insert ، @Delete و @Update . برای هر چیز دیگری، حاشیه نویسی @Query وجود دارد. می توانید هر درخواستی را که توسط SQLite پشتیبانی می شود بنویسید.
به عنوان یک امتیاز اضافی، هنگامی که پرس و جوهای خود را در Android Studio ایجاد می کنید، کامپایلر پرس و جوهای SQL شما را برای خطاهای نحوی بررسی می کند.
برای پایگاه داده ردیاب خواب شبهای خواب، باید بتوانید کارهای زیر را انجام دهید:
- درج شب های جدید
- برای بهروزرسانی زمان پایان و رتبهبندی کیفیت، یک شب موجود را بهروزرسانی کنید .
- یک شب خاص بر اساس کلید آن دریافت کنید .
- تمام شب ها را دریافت کنید تا بتوانید آنها را نمایش دهید.
- آخرین شب را دریافت کنید.
- تمام ورودی های پایگاه داده را حذف کنید .
مرحله 1: SleepDatabase DAO را ایجاد کنید
- در بسته
database،SleepDatabaseDao.ktباز کنید. - توجه داشته باشید که
interfaceSleepDatabaseDaoبا@Daoحاشیه نویسی شده است. همه DAO ها باید با کلمه کلیدی@Daoحاشیه نویسی شوند.
@Dao
interface SleepDatabaseDao {}- در داخل بدنه رابط، یک حاشیه نویسی
@Insertاضافه کنید. در زیر@Insert، یک تابعinsert()اضافه کنید که نمونه ای از کلاسEntitySleepNightرا می گیرد. به عنوان استدلال آن
همین است.Roomهمه کدهای لازم را برای درجSleepNightدر پایگاه داده تولید می کند. هنگامی کهinsert()از کد Kotlin خود فرا می خوانید،Roomیک پرس و جوی SQL را برای درج موجودیت در پایگاه داده اجرا می کند. (توجه: می توانید تابع را هر چیزی که می خواهید فراخوانی کنید.)
@Insert
fun insert(night: SleepNight)- برای یک
SleepNightیک حاشیه نویسی@Updateبا یک تابعupdate()اضافه کنید. نهادی که بهروزرسانی میشود، نهادی است که دارای کلید مشابهی است که به آن ارسال شده است. میتوانید برخی یا همه ویژگیهای دیگر آن نهاد را بهروزرسانی کنید.
@Update
fun update(night: SleepNight) هیچ حاشیه نویسی راحتی برای عملکرد باقی مانده وجود ندارد، بنابراین باید از حاشیه نویسی @Query استفاده کنید و پرس و جوهای SQLite را تهیه کنید.
- یک حاشیه نویسی
@Queryبا تابعget()اضافه کنید که یکkeyLongمی گیرد آرگومان و یکSleepNightقابل تهی را برمی گرداند. خطای یک پارامتر از دست رفته را خواهید دید.
@Query
fun get(key: Long): SleepNight?- پرس و جو به عنوان پارامتر رشته ای به حاشیه نویسی ارائه می شود. یک پارامتر به
@Queryاضافه کنید. آن را بهStringتبدیل کنید که یک کوئری SQLite است.
- همه ستون ها را از جدول
daily_sleep_quality_tableانتخاب کنید -
WHEREnightIdبا آرگومانkey: مطابقت دارد.
به:keyتوجه کنید. برای ارجاع آرگومان های تابع از علامت دو نقطه در پرس و جو استفاده می کنید.
("SELECT * from daily_sleep_quality_table WHERE nightId = :key")- یک
@Queryدیگر با یک تابعclear()و یک جستجوی SQLite اضافه کنید تا همه چیز را ازdaily_sleep_quality_tableDELETE. این پرس و جو خود جدول را حذف نمی کند.
حاشیهنویسی@Deleteیک مورد را حذف میکند و میتوانید از@Deleteاستفاده کنید و فهرستی از شبها را برای حذف ارائه دهید. اشکال این است که شما باید آنچه را در جدول وجود دارد واکشی کنید یا بدانید. حاشیهنویسی@Deleteبرای حذف ورودیهای خاص عالی است، اما برای پاک کردن همه ورودیهای یک جدول کارآمد نیست.
@Query("DELETE FROM daily_sleep_quality_table")
fun clear()- یک
@Queryبا تابعgetTonight()اضافه کنید.SleepNightرا که توسطgetTonight()برگردانده شده است تهی کنید تا تابع بتواند مواردی را که جدول خالی است کنترل کند. (جدول در ابتدا و پس از پاک شدن داده ها خالی است.)
برای دریافت "tonight" از پایگاه داده، یک پرس و جوی SQLite بنویسید که اولین عنصر لیستی از نتایج را که بر اساسnightIdمرتب شده اند به ترتیب نزولی برمی گرداند. ازLIMIT 1برای برگرداندن تنها یک عنصر استفاده کنید.
@Query("SELECT * FROM daily_sleep_quality_table ORDER BY nightId DESC LIMIT 1")
fun getTonight(): SleepNight?- یک
@Queryبا تابعgetAllNights()اضافه کنید:
- از پرس و جوی SQLite بخواهید همه ستون ها را از
daily_sleep_quality_tableبه ترتیب نزولی برگرداند. - از
getAllNights()لیستی از موجودیت هایSleepNightرا به عنوانLiveDataبازگردانید.RoomاینLiveDataرا برای شما بهروز نگه میدارد، به این معنی که فقط یک بار باید صریحاً دادهها را دریافت کنید. - ممکن است لازم باشد
LiveDataازandroidx.lifecycle.LiveDataوارد کنید.
@Query("SELECT * FROM daily_sleep_quality_table ORDER BY nightId DESC")
fun getAllNights(): LiveData<List<SleepNight>>- اگرچه هیچ تغییر قابل مشاهده ای نمی بینید، برنامه خود را اجرا کنید تا مطمئن شوید که هیچ خطایی ندارد.
در این کار، شما یک پایگاه داده Room ایجاد می کنید که از Entity و DAO که در کار قبلی ایجاد کرده اید استفاده می کند.
شما باید یک کلاس دارنده پایگاه داده انتزاعی ایجاد کنید که با @Database حاشیه نویسی شده باشد. این کلاس یک متد دارد که اگر پایگاه داده وجود نداشته باشد نمونه ای از پایگاه داده را ایجاد می کند یا یک مرجع به پایگاه داده موجود برمی گرداند.
گرفتن یک پایگاه داده Room کمی دخیل است، بنابراین قبل از شروع با کد، روند کلی در اینجا آمده است:
- یک کلاس
public abstractایجاد کنید کهextends RoomDatabase. این کلاس به عنوان دارنده پایگاه داده عمل می کند. کلاس انتزاعی است، زیراRoomپیاده سازی را برای شما ایجاد می کند. - کلاس را با
@Databaseحاشیه نویسی کنید. در آرگومان ها، موجودیت های پایگاه داده را اعلام کرده و شماره نسخه را تنظیم کنید. - در داخل یک شی
companion، یک متد یا ویژگی انتزاعی تعریف کنید که یکSleepDatabaseDaoبرمی گرداند.Roomبرای شما بدن تولید می کند. - شما فقط به یک نمونه از پایگاه داده
Roomبرای کل برنامه نیاز دارید، بنابراینRoomDatabaseیک تکتونه کنید. - تنها در صورتی که پایگاه داده وجود نداشته باشد، از سازنده پایگاه داده
Roomبرای ایجاد پایگاه داده استفاده کنید. در غیر این صورت، پایگاه داده موجود را برگردانید.
مرحله 1: ایجاد پایگاه داده
- در بسته
database،SleepDatabase.ktباز کنید. - در فایل، یک کلاس
abstractبه نامSleepDatabaseایجاد کنید کهRoomDatabaseگسترش می دهد.
کلاس را با@Databaseحاشیه نویسی کنید.
@Database()
abstract class SleepDatabase : RoomDatabase() {}- خطای موجودیت ها و پارامترهای نسخه را مشاهده خواهید کرد. حاشیه نویسی
@Databaseبه چندین آرگومان نیاز دارد تاRoomبتواند پایگاه داده را بسازد.
-
SleepNightبه عنوان تنها مورد با لیستentitiesعرضه کنید. -
versionرا به عنوان1تنظیم کنید . هر زمان که شما طرح را تغییر دهید، باید شماره نسخه را افزایش دهید. -
exportSchemaرویfalseقرار دهید تا نسخه پشتیبانگیری از تاریخچه نسخه طرحواره حفظ نشود.
entities = [SleepNight::class], version = 1, exportSchema = false- پایگاه داده باید در مورد DAO بداند. در داخل بدنه کلاس، یک مقدار انتزاعی را اعلام کنید که
SleepDatabaseDaoبرمی گرداند. شما می توانید چندین DAO داشته باشید.
abstract val sleepDatabaseDao: SleepDatabaseDao- در زیر آن، یک شیء
companionتعریف کنید. شیء companion به مشتریان اجازه می دهد تا بدون نمونه سازی کلاس به متدهای ایجاد یا دریافت پایگاه داده دسترسی داشته باشند. از آنجایی که تنها هدف این کلاس ارائه یک پایگاه داده است، هیچ دلیلی برای نمونه سازی آن وجود ندارد.
companion object {}- در داخل شی
companion، یک متغیر تهی پذیر خصوصیINSTANCEبرای پایگاه داده اعلام کنید و آن را بهnullمقداردهی کنید. متغیرINSTANCEیک مرجع به پایگاه داده، پس از ایجاد پایگاه داده نگه می دارد. این به شما کمک می کند تا از باز کردن مکرر اتصالات به پایگاه داده جلوگیری کنید که گران است.
INSTANCE با @Volatile حاشیه نویسی کنید. مقدار متغیر فرار هرگز در حافظه پنهان ذخیره نمی شود و تمام نوشتن و خواندن به حافظه اصلی و از آن انجام می شود. این کمک می کند مطمئن شوید که مقدار INSTANCE همیشه به روز است و برای همه رشته های اجرایی یکسان است. این بدان معناست که تغییرات ایجاد شده توسط یک رشته به INSTANCE برای همه رشتههای دیگر بلافاصله قابل مشاهده است، و شما موقعیتی را دریافت نمیکنید که مثلاً دو رشته هر کدام یک موجودیت مشابه را در حافظه پنهان بهروزرسانی کنند، که مشکل ایجاد میکند.
@Volatile
private var INSTANCE: SleepDatabase? = null- در زیر
INSTANCE، هنوز در داخل شیءcompanion، یک متدgetInstance()با پارامترContextتعریف کنید که سازنده پایگاه داده به آن نیاز دارد. یک نوعSleepDatabaseرا برگردانید. یک خطایی خواهید دید زیراgetInstance()هنوز چیزی را بر نمی گرداند.
fun getInstance(context: Context): SleepDatabase {}- داخل
getInstance()یک بلوکsynchronized{}اضافه کنید.thisرا پاس کنید تا بتوانید به متن دسترسی داشته باشید.
چندین رشته به طور بالقوه می توانند به طور همزمان یک نمونه پایگاه داده را درخواست کنند که منجر به ایجاد دو پایگاه داده به جای یک پایگاه داده شود. این مشکل به احتمال زیاد در این نمونه برنامه اتفاق نمی افتد، اما برای یک برنامه پیچیده تر امکان پذیر است. بسته بندی کد برایsynchronizedپایگاه داده به این معنی است که تنها یک رشته اجرا در هر زمان می تواند وارد این بلوک کد شود، که مطمئن می شود پایگاه داده فقط یک بار مقداردهی اولیه می شود.
synchronized(this) {}- در داخل بلوک همگامسازی شده، مقدار فعلی
INSTANCEرا در یکinstanceمتغیر محلی کپی کنید. این برای استفاده از قابلیت پخش هوشمند است که فقط برای متغیرهای محلی در دسترس است.
var instance = INSTANCE- در داخل بلوک
synchronized، نمونهای را در انتهای بلوکsynchronizedreturn instance. خطای عدم تطابق نوع بازگشتی را نادیده بگیرید. پس از اتمام کار هرگز نخواهید برگشت.
return instance- بالای دستور
return، یک دستورifاضافه کنید تا بررسی کنید که آیاinstanceصفر است یا نه، یعنی هنوز پایگاه داده ای وجود ندارد.
if (instance == null) {}- اگر
instancenullاست، از سازنده پایگاه داده برای دریافت پایگاه داده استفاده کنید. در بدنه دستورif،Room.databaseBuilderرا فراخوانی کنید و متنی را که در آن ارسال کردید، کلاس پایگاه داده و یک نام برای پایگاه داده،sleep_history_databaseارائه کنید. برای حذف خطا، باید یک استراتژی مهاجرت وbuild()در مراحل زیر اضافه کنید.
instance = Room.databaseBuilder(
context.applicationContext,
SleepDatabase::class.java,
"sleep_history_database")- استراتژی مهاجرت مورد نیاز را به سازنده اضافه کنید.
.fallbackToDestructiveMigration()استفاده کنید.
به طور معمول، شما باید یک شی مهاجرت را با یک استراتژی مهاجرت برای زمانی که طرحواره تغییر می کند ارائه دهید. یک شیء مهاجرتی ، شیئی است که تعریف میکند چگونه همه ردیفها را با طرحواره قدیمی بگیرید و آنها را به ردیفهایی در طرح جدید تبدیل کنید، به طوری که هیچ دادهای از بین نرود. مهاجرت فراتر از محدوده این کد آزمایشگاه است. یک راه حل ساده، تخریب و بازسازی پایگاه داده است، به این معنی که داده ها از بین می روند.
.fallbackToDestructiveMigration()- در نهایت،
.build()را فراخوانی کنید.
.build()INSTANCE = instanceبه عنوان مرحله نهایی داخل دستورifاختصاص دهید.
INSTANCE = instance- کد نهایی شما باید به شکل زیر باشد:
@Database(entities = [SleepNight::class], version = 1, exportSchema = false)
abstract class SleepDatabase : RoomDatabase() {
abstract val sleepDatabaseDao: SleepDatabaseDao
companion object {
@Volatile
private var INSTANCE: SleepDatabase? = null
fun getInstance(context: Context): SleepDatabase {
synchronized(this) {
var instance = INSTANCE
if (instance == null) {
instance = Room.databaseBuilder(
context.applicationContext,
SleepDatabase::class.java,
"sleep_history_database"
)
.fallbackToDestructiveMigration()
.build()
INSTANCE = instance
}
return instance
}
}
}
}- کد خود را بسازید و اجرا کنید.
شما اکنون تمام بلوک های سازنده برای کار با پایگاه داده Room خود را دارید. این کد کامپایل می شود و اجرا می شود، اما شما هیچ راهی برای تشخیص کارکرد آن ندارید. بنابراین، این زمان خوبی برای اضافه کردن چند تست اساسی است.
مرحله 2: SleepDatabase را تست کنید
در این مرحله، تست های ارائه شده را برای بررسی کارکرد پایگاه داده خود اجرا می کنید. این کمک می کند تا اطمینان حاصل شود که پایگاه داده قبل از ساختن روی آن کار می کند. تست های ارائه شده پایه هستند. برای یک برنامه تولیدی، شما باید تمام عملکردها و پرس و جوها را در همه DAO ها اعمال کنید.
برنامه شروع کننده حاوی یک پوشه AndroidTest است. این پوشه AndroidTest شامل تستهای واحدی است که شامل ابزار دقیق اندروید میشود، که روشی فانتزی برای گفتن این است که تستها به چارچوب اندروید نیاز دارند، بنابراین باید آزمایشها را روی یک دستگاه فیزیکی یا مجازی اجرا کنید. البته، میتوانید تستهای واحد خالص را نیز ایجاد و اجرا کنید که شامل فریمورک اندروید نیست.
- در Android Studio، در پوشه androidTest ، فایل SleepDatabaseTest را باز کنید.
- برای لغو کامنت کد، همه کدهای نظر داده شده را انتخاب کنید و میانبر صفحه کلید
Cmd+/یاControl+/را فشار دهید. - به فایل نگاهی بیندازید.
در اینجا یک بررسی سریع از کد آزمایشی وجود دارد، زیرا این کد دیگری است که می توانید مجدداً از آن استفاده کنید:
-
SleepDabaseTestیک کلاس آزمایشی است . - حاشیه نویسی
@RunWith، اجرای آزمایشی را مشخص می کند، که برنامه ای است که تست ها را تنظیم و اجرا می کند. - در طول راهاندازی، تابع مشروح شده با
@Beforeاجرا میشود و یکSleepDatabaseدر حافظه باSleepDatabaseDaoایجاد میکند. "In-Memory" به این معنی است که این پایگاه داده در سیستم فایل ذخیره نمی شود و پس از اجرای آزمایش ها حذف می شود. - همچنین هنگام ساخت پایگاه داده درون حافظه، کد روش دیگری را که مربوط به تست است،
allowMainThreadQueriesفراخوانی می کند. به طور پیش فرض، اگر سعی کنید کوئری ها را در رشته اصلی اجرا کنید، با خطا مواجه می شوید. این روش به شما اجازه می دهد تا تست هایی را روی رشته اصلی اجرا کنید که فقط باید در حین تست انجام دهید. - در یک روش آزمایشی که با
@Testحاشیه نویسی شده است، یکSleepNightرا ایجاد، درج و بازیابی می کنید و اظهار می کنید که آنها یکسان هستند. اگر مشکلی پیش آمد، یک استثنا بیندازید. در یک تست واقعی، چندین@Testخواهید داشت روش ها - وقتی تست انجام شد، تابع مشروح شده با
@Afterبرای بستن پایگاه داده اجرا می شود.
- روی فایل تست در پنجره Project کلیک راست کرده و Run 'SleepDatabaseTest' را انتخاب کنید.
- پس از اجرای تستها، در پنل SleepDatabaseTest تأیید کنید که تمام تستها قبول شدهاند.

از آنجایی که تمام تست ها گذرانده شده اند، اکنون چندین چیز را می دانید:
- پایگاه داده به درستی ایجاد می شود.
- می توانید یک
SleepNightرا در پایگاه داده وارد کنید. - می توانید
SleepNightرا برگردانید. -
SleepNightارزش مناسبی برای کیفیت دارد.
پروژه اندروید استودیو: TrackMySleepQualityRoomAndTesting
هنگام آزمایش یک پایگاه داده، باید تمام روش های تعریف شده در DAO را اعمال کنید. برای تکمیل تست ، تست هایی را اضافه و اجرا کنید تا روش های دیگر DAO را اعمال کنید.
- جداول خود را به عنوان کلاس های داده مشروح شده با
@Entityتعریف کنید. ویژگی های حاشیه نویسی شده با@ColumnInfoرا به عنوان ستون در جداول تعریف کنید. - یک شی دسترسی به داده (DAO) را به عنوان یک رابط مشروح شده با
@Daoتعریف کنید. DAO توابع Kotlin را به پرس و جوهای پایگاه داده نگاشت می کند. - از حاشیه نویسی برای تعریف توابع
@Insert،@Deleteو@Updateاستفاده کنید. - از حاشیه نویسی
@Queryبا رشته پرس و جو SQLite به عنوان پارامتر برای هر جستار دیگر استفاده کنید. - یک کلاس انتزاعی ایجاد کنید که دارای تابع
getInstance()باشد که پایگاه داده را برمی گرداند. - از تست های ابزاری برای آزمایش اینکه پایگاه داده و DAO شما مطابق انتظار کار می کنند استفاده کنید. می توانید از تست های ارائه شده به عنوان الگو استفاده کنید.
دوره بی ادبی:
مستندات برنامه نویس اندروید:
-
RoomDatabase -
Database(یادداشت ها) - میتوانید از درخواستهای خام با
Roomاستفاده کنید -
Roomdatabase.Builder - آموزش تست
- کلاس
SQLiteDatabase -
Dao - کتابخانه ماندگاری
Room
سایر اسناد و مقالات:
این بخش، تکالیف احتمالی را برای دانشآموزانی که در این آزمایشگاه کد به عنوان بخشی از دورهای که توسط یک مربی هدایت میشود، کار میکنند، فهرست میکند. این وظیفه مربی است که موارد زیر را انجام دهد:
- در صورت نیاز تکالیف را تعیین کنید.
- نحوه ارسال تکالیف را با دانش آموزان در میان بگذارید.
- تکالیف را نمره دهید.
مربیان میتوانند از این پیشنهادات به اندازهای که میخواهند استفاده کنند، و باید با خیال راحت هر تکلیف دیگری را که فکر میکنند مناسب است، محول کنند.
اگر به تنهایی از طریق این کدها کار می کنید، از این تکالیف برای آزمایش دانش خود استفاده کنید.
به این سوالات پاسخ دهید
سوال 1
چگونه نشان می دهید که یک کلاس یک موجودیت را برای ذخیره در پایگاه داده Room نشان می دهد؟
- کلاس را گسترش دهید
DatabaseEntity. - کلاس را با
@Entityحاشیه نویسی کنید. - کلاس را با
@Databaseحاشیه نویسی کنید. - کلاس را گسترش دهید
RoomEntityو همچنین کلاس را با@Roomحاشیه نویسی کنید.
سوال 2
DAO (شیء دسترسی به داده) رابطی است که Room از آن برای نگاشت توابع Kotlin به کوئری های پایگاه داده استفاده می کند.
چگونه نشان می دهید که یک رابط یک DAO برای پایگاه داده Room را نشان می دهد؟
- رابط را گسترش دهید
RoomDAO. - رابط را گسترش دهید
EntityDao، سپس متدDaoConnection()پیاده سازی کنید. - رابط کاربری را با
@Daoحاشیه نویسی کنید. - رابط را با
@RoomConnectionحاشیه نویسی کنید.
سوال 3
کدام یک از عبارات زیر در مورد پایگاه داده Room درست است؟ همه موارد کاربردی را انتخاب کنید.
- می توانید جداول را برای پایگاه داده
Roomبه عنوان کلاس های داده مشروح تعریف کنید. - اگر
LiveDataاز یک پرس و جو برگردانید،Roomدر صورت تغییرLiveDataLiveDataبرای شما به روز نگه می دارد. - هر پایگاه داده
Roomباید یک و تنها یک DAO داشته باشد. - برای شناسایی یک کلاس به عنوان پایگاه داده
Room، آن را به زیر کلاسRoomDatabaseتبدیل کنید و آن را با@Databaseحاشیه نویسی کنید.
سوال 4
کدام یک از حاشیه نویسی های زیر را می توانید در رابط @Dao خود استفاده کنید؟ همه موارد کاربردی را انتخاب کنید.
-
@Get -
@Update -
@Insert -
@Query
سوال 5
چگونه می توانید بررسی کنید که پایگاه داده شما کار می کند؟ همه موارد کاربردی را انتخاب کنید.
- تست های ابزاری را بنویسید.
- نوشتن و اجرای برنامه را تا نمایش داده ها ادامه دهید.
- فراخوانی متدهای موجود در رابط DAO را با فراخوانی متدهای معادل در کلاس
Entityجایگزین کنید. - تابع
verifyDatabase()ارائه شده توسط کتابخانهRoomرا اجرا کنید.
شروع به درس بعدی:
برای پیوند به سایر کدهای این دوره، به صفحه فرود کد لبههای کد پایه Android Kotlin Fundamentals مراجعه کنید.
این کد لبه بخشی از دوره آموزشی Android Kotlin Fundamentals است. اگر به ترتیب روی کدها کار کنید، بیشترین ارزش را از این دوره خواهید گرفت. همه کد لبه های دوره در صفحه فرود کد لبه های Android Kotlin Fundamentals فهرست شده اند.
مقدمه
بیشتر برنامهها دادههایی دارند که حتی پس از بستن برنامه توسط کاربر، باید حفظ شوند. برای مثال، برنامه ممکن است فهرست پخش، فهرستی از اقلام بازی، سوابق هزینهها و درآمد، فهرستی از صورتهای فلکی، یا دادههای خواب را در طول زمان ذخیره کند. معمولاً از یک پایگاه داده برای ذخیره داده های پایدار استفاده می کنید.
Room یک کتابخانه پایگاه داده است که بخشی از Android Jetpack است. Room بسیاری از کارهای راه اندازی و پیکربندی یک پایگاه داده را بر عهده می گیرد و این امکان را برای برنامه شما فراهم می کند تا با استفاده از فراخوانی های تابع معمولی با پایگاه داده تعامل داشته باشد. در زیر هود، Room یک لایه انتزاعی در بالای پایگاه داده SQLite است. اصطلاحات Room ، و نحو پرس و جو برای پرس و جوهای پیچیده تر، از مدل SQLite پیروی می کنند.
تصویر زیر نشان می دهد که چگونه پایگاه داده Room با معماری کلی توصیه شده در این دوره مطابقت دارد.

آنچه از قبل باید بدانید
شما باید با این موارد آشنا باشید:
- ساخت یک رابط کاربری اولیه (UI) برای یک برنامه اندروید
- استفاده از فعالیت ها، قطعات و نماها.
- پیمایش بین قطعات و استفاده از Safe Args (یک افزونه Gradle) برای انتقال داده ها بین قطعات.
- مدلها، کارخانههای مشاهده مدل، و
LiveDataو ناظران آن را مشاهده کنید. این مباحث مولفه های معماری در یک کدآلب قبلی در این دوره پوشش داده شده است. - درک اولیه از پایگاه داده SQL و زبان SQLite. برای یک مرور کلی یا تازهسازی به SQLite Primer مراجعه کنید.
چیزی که یاد خواهید گرفت
- نحوه ایجاد و تعامل با پایگاه داده
Roomبرای ماندگاری داده ها. - نحوه ایجاد یک کلاس داده که یک جدول را در پایگاه داده تعریف می کند.
- نحوه استفاده از یک شی دسترسی به داده (DAO) برای نگاشت توابع Kotlin به پرس و جوهای SQL.
- چگونه آزمایش کنیم که آیا پایگاه داده شما کار می کند یا خیر.
کاری که خواهی کرد
- یک پایگاه داده
Roomبا یک رابط برای داده های خواب شبانه ایجاد کنید. - پایگاه داده را با استفاده از تست های ارائه شده تست کنید.
در این نرم افزار کد، بخش پایگاه داده یک برنامه را می سازید که کیفیت خواب را ردیابی می کند. این برنامه از یک پایگاه داده برای ذخیره داده های خواب در طول زمان استفاده می کند.
این برنامه دارای دو صفحه است که با قطعات نشان داده شده است، همانطور که در شکل زیر نشان داده شده است.
اولین صفحه نمایش داده شده در سمت چپ دارای دکمه هایی برای شروع و توقف ردیابی است. صفحه نمایش تمام داده های خواب کاربر را نشان می دهد. دکمه Clear تمام داده هایی را که برنامه برای کاربر جمع آوری کرده است برای همیشه حذف می کند.
صفحه دوم، نشان داده شده در سمت راست، برای انتخاب رتبه بندی کیفیت خواب است. در برنامه، امتیاز به صورت عددی نشان داده می شود. برای اهداف توسعه، برنامه هم نمادهای چهره و هم معادل های عددی آنها را نشان می دهد.
جریان کاربر به شرح زیر است:
- کاربر برنامه را باز می کند و با صفحه ردیابی خواب نمایش داده می شود.
- کاربر روی دکمه Start ضربه می زند. این زمان شروع را ثبت کرده و نمایش می دهد. دکمه Start غیرفعال است و دکمه Stop فعال است.
- کاربر روی دکمه Stop ضربه می زند. این کار زمان پایان را ثبت می کند و صفحه با کیفیت خواب را باز می کند.
- کاربر یک نماد کیفیت خواب را انتخاب می کند. صفحه بسته می شود و صفحه ردیابی زمان پایان خواب و کیفیت خواب را نشان می دهد. دکمه Stop غیرفعال و دکمه Start فعال است. برنامه برای یک شب دیگر آماده است.
- دکمه Clear هر زمان که داده ای در پایگاه داده وجود داشته باشد فعال می شود. هنگامی که کاربر روی دکمه Clear ضربه میزند، تمام دادههای او بدون مراجعه پاک میشوند - "آیا مطمئن هستید؟" وجود ندارد. پیام
این برنامه از معماری ساده شده استفاده می کند، همانطور که در زیر در زمینه معماری کامل نشان داده شده است. این برنامه فقط از اجزای زیر استفاده می کند:
- کنترلر رابط کاربری
- مشاهده مدل و
LiveData - پایگاه داده اتاق
مرحله 1: برنامه شروع را دانلود و اجرا کنید
- برنامه TrackMySleepQuality-Starter را از GitHub دانلود کنید.
- برنامه را بسازید و اجرا کنید. برنامه رابط کاربری بخش
SleepTrackerFragmentرا نشان می دهد، اما داده ای ندارد. دکمه ها به ضربه ها پاسخ نمی دهند.
مرحله 2: برنامه شروع را بررسی کنید
- به فایل های Gradle نگاهی بیندازید:
- فایل پروژه Gradle
در فایلbuild.gradleدر سطح پروژه، به متغیرهایی که نسخه های کتابخانه را مشخص می کنند توجه کنید. نسخه های استفاده شده در برنامه استارتر به خوبی با هم کار می کنند و با این برنامه به خوبی کار می کنند. تا زمانی که این کد لبه را تمام کنید، ممکن است Android Studio از شما بخواهد که برخی از نسخه ها را به روز کنید. این به شما بستگی دارد که آیا می خواهید نسخه های موجود در برنامه را به روز کنید یا از آن استفاده کنید. اگر با خطاهای کامپایل "عجیب" مواجه شدید، سعی کنید از ترکیب نسخه های کتابخانه ای که برنامه راه حل نهایی استفاده می کند استفاده کنید. - فایل ماژول Gradle. به وابستگیهای ارائهشده برای همه کتابخانههای Android Jetpack، از جمله
Room، و وابستگیهای کوروتینها توجه کنید.
- به بسته ها و UI نگاهی بیندازید. برنامه بر اساس عملکرد ساختار یافته است. این بسته حاوی فایلهای نگهدارنده است که در آن کد را در این سری از کدها اضافه خواهید کرد.
- بسته
database، برای همه کدهای مربوط به پایگاه دادهRoom. - بستههای
sleepqualityوsleeptrackerشامل قطعه، مدل view و کارخانه مدل view برای هر صفحه هستند .
- به فایل
Util.ktنگاهی بیندازید، که حاوی توابعی برای کمک به نمایش داده های با کیفیت خواب است. برخی از کدها به دلیل ارجاع به یک مدل view که بعداً ایجاد می کنید، توضیح داده می شود. - به پوشه androidTest (
SleepDatabaseTest.kt) نگاهی بیندازید. شما از این تست برای بررسی اینکه پایگاه داده طبق برنامه کار می کند استفاده خواهید کرد.
در اندروید، دادهها در کلاسهای داده نمایش داده میشوند و دادهها با استفاده از فراخوانی تابع قابل دسترسی و تغییر هستند. با این حال، در دنیای پایگاه داده، شما به نهادها و پرس و جو نیاز دارید.
- یک موجودیت یک شی یا مفهوم و خصوصیات آن را برای ذخیره در پایگاه داده نشان می دهد. یک کلاس موجودیت یک جدول را تعریف می کند و هر نمونه از آن کلاس نشان دهنده یک ردیف در جدول است. هر ویژگی یک ستون را تعریف می کند. در برنامه شما، نهاد اطلاعاتی در مورد یک شب خواب نگه می دارد.
- پرس و جو درخواست داده یا اطلاعات از جدول پایگاه داده یا ترکیبی از جداول یا درخواستی برای انجام عملی بر روی داده است. پرس و جوهای رایج برای دریافت، درج و به روز رسانی موجودیت ها هستند. برای مثال، میتوانید برای تمام شبهای خواب ثبت شده، مرتبسازیشده بر اساس زمان شروع، پرس و جو کنید.
Room همه کار سختی را برای شما انجام می دهد تا از کلاس های داده Kotlin به موجودیت هایی که می توانند در جداول SQLite ذخیره شوند و از اعلان های تابع تا پرس و جوهای SQL را به دست آورید.
شما باید هر موجودیت را به عنوان یک کلاس داده مشروح، و تعاملات را به عنوان یک رابط مشروح شده، یک شی دسترسی به داده (DAO) تعریف کنید. Room از این کلاس های حاشیه نویسی برای ایجاد جداول در پایگاه داده و پرس و جوهایی که روی پایگاه داده عمل می کنند استفاده می کند.

مرحله 1: موجودیت SleepNight را ایجاد کنید
در این کار، یک شب خواب را به عنوان یک کلاس داده مشروح تعریف می کنید.
برای یک شب خواب، باید زمان شروع، زمان پایان و رتبه بندی کیفیت را ثبت کنید.
و برای شناسایی منحصر به فرد شب به یک شناسه نیاز دارید.
- در بسته
database، فایلSleepNight.ktرا پیدا کرده و باز کنید. - کلاس داده
SleepNightرا با پارامترهایی برای شناسه، زمان شروع (بر حسب میلی ثانیه)، زمان پایان (بر حسب میلی ثانیه) و رتبه بندی عددی کیفیت خواب ایجاد کنید.
- شما باید
sleepQualityرا مقداردهی اولیه کنید، بنابراین آن را روی-1تنظیم کنید، که نشان می دهد هیچ داده با کیفیتی جمع آوری نشده است. - شما همچنین باید زمان پایان را مقداردهی اولیه کنید. آن را روی زمان شروع تنظیم کنید تا نشان دهد که هنوز زمان پایانی ثبت نشده است.
data class SleepNight(
var nightId: Long = 0L,
val startTimeMilli: Long = System.currentTimeMillis(),
var endTimeMilli: Long = startTimeMilli,
var sleepQuality: Int = -1
)- قبل از اعلان کلاس، کلاس داده را با
@Entityحاشیه نویسی کنید. نام جدول راdaily_sleep_quality_tableبگذارید. آرگومانtableNameاختیاری است، اما توصیه می شود. می توانید سایر استدلال ها را در مستندات جستجو کنید.
در صورت درخواست،Entityو تمام حاشیه نویسی های دیگر را از کتابخانهandroidxوارد کنید.
@Entity(tableName = "daily_sleep_quality_table")
data class SleepNight(...)- برای شناسایی
nightIdبه عنوان کلید اصلی، ویژگیnightIdرا با@PrimaryKeyحاشیه نویسی کنید. پارامترautoGenerateرویtrueتنظیم کنید تاRoomبرای هر موجودیت شناسه تولید کند. این تضمین می کند که شناسه هر شب منحصر به فرد است.
@PrimaryKey(autoGenerate = true)
var nightId: Long = 0L,...- ویژگی های باقی مانده را با
@ColumnInfoحاشیه نویسی کنید. مطابق شکل زیر نام ویژگی ها را با استفاده از پارامترها سفارشی کنید.
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
@Entity(tableName = "daily_sleep_quality_table")
data class SleepNight(
@PrimaryKey(autoGenerate = true)
var nightId: Long = 0L,
@ColumnInfo(name = "start_time_milli")
val startTimeMilli: Long = System.currentTimeMillis(),
@ColumnInfo(name = "end_time_milli")
var endTimeMilli: Long = startTimeMilli,
@ColumnInfo(name = "quality_rating")
var sleepQuality: Int = -1
)- کد خود را بسازید و اجرا کنید تا مطمئن شوید که هیچ خطایی ندارد.
در این کار، یک شی دسترسی به داده (DAO) را تعریف می کنید. در اندروید، DAO روشهای آسانی را برای درج، حذف و بهروزرسانی پایگاه داده ارائه میکند.
هنگامی که از پایگاه داده Room استفاده می کنید، با تعریف و فراخوانی توابع Kotlin در کد خود، پایگاه داده را پرس و جو می کنید. این توابع Kotlin به پرس و جوهای SQL نگاشت می شوند. شما آن نگاشتها را در یک DAO با استفاده از حاشیه نویسی تعریف می کنید و Room کد لازم را ایجاد می کند.
یک DAO را به عنوان تعریف یک رابط سفارشی برای دسترسی به پایگاه داده خود در نظر بگیرید.
برای عملیات رایج پایگاه داده، کتابخانه Room حاشیه نویسی های راحت را ارائه می دهد، مانند @Insert ، @Delete و @Update . برای هر چیز دیگری، حاشیه نویسی @Query وجود دارد. می توانید هر درخواستی را که توسط SQLite پشتیبانی می شود بنویسید.
به عنوان یک امتیاز اضافی، هنگامی که پرس و جوهای خود را در Android Studio ایجاد می کنید، کامپایلر پرس و جوهای SQL شما را برای خطاهای نحوی بررسی می کند.
برای پایگاه داده ردیاب خواب شبهای خواب، باید بتوانید کارهای زیر را انجام دهید:
- درج شب های جدید
- برای بهروزرسانی زمان پایان و رتبهبندی کیفیت، یک شب موجود را بهروزرسانی کنید .
- یک شب خاص بر اساس کلید آن دریافت کنید .
- تمام شب ها را دریافت کنید تا بتوانید آنها را نمایش دهید.
- آخرین شب را دریافت کنید.
- تمام ورودی های پایگاه داده را حذف کنید .
مرحله 1: SleepDatabase DAO را ایجاد کنید
- در بسته
database،SleepDatabaseDao.ktباز کنید. - توجه کنید که
interfaceSleepDatabaseDaoبا@Daoحاشیه نویسی شده است. همه DAO ها باید با کلمه کلیدی@Daoحاشیه نویسی شوند.
@Dao
interface SleepDatabaseDao {}- در داخل بدنه رابط ، حاشیه نویسی
@Insertرا اضافه کنید. در زیر@Insert، یک تابعinsert()اضافه کنید که نمونه ای ازSleepNightClassEntityرا در بر می گیرد به عنوان استدلال خود
همین است.Roomتمام کد لازم را برای وارد کردنSleepNightدر پایگاه داده ایجاد می کند. هنگامی که از کد Kotlin خودinsert()تماس می گیرید ،Roomیک پرس و جو SQL را برای وارد کردن موجودیت در پایگاه داده اجرا می کند. (توجه: می توانید هر چیزی را که می خواهید با عملکرد تماس بگیرید.)
@Insert
fun insert(night: SleepNight)- برای یک
SleepNightیک یادداشت@Updateرا با یک عملکردupdate()اضافه کنید. موجودی که به روز شده است ، موجودی است که همان کلید را دارد که در آن منتقل شده است. می توانید برخی یا تمام خصوصیات دیگر موجودیت را به روز کنید.
@Update
fun update(night: SleepNight) هیچ گونه حاشیه نویسی برای عملکرد باقی مانده وجود ندارد ، بنابراین شما باید از یادداشت های @Query و عرضه SQLite استفاده کنید.
- یک یادداشت
@Queryرا با یک عملکردget()اضافه کنید که یکkeyLongطول می کشد استدلال و یکSleepNightقابل برگشت را برمی گرداند. خطایی برای یک پارامتر گمشده مشاهده خواهید کرد.
@Query
fun get(key: Long): SleepNight?- پرس و جو به عنوان یک پارامتر رشته برای حاشیه نویسی تهیه می شود. یک پارامتر به
@Queryاضافه کنید. آن راStringدرست کنید که یک پرس و جو sqlite باشد.
- همه ستون ها را از
daily_sleep_quality_tableانتخاب کنید -
WHEREnightIdبا: استدلالkeyمطابقت دارد.
توجه کنید:key. شما از نماد روده بزرگ در پرس و جو برای آرگومان های مرجع در عملکرد استفاده می کنید.
("SELECT * from daily_sleep_quality_table WHERE nightId = :key")- your
@Queryبا یک عملکردclear()و یک پرس و جو sqlite اضافه کنید تا همه چیز را ازdaily_sleep_quality_tableDELETE. این پرس و جو خود جدول را حذف نمی کند.
حاشیه@Deletedelete یک مورد را حذف می کند ، و می توانید@Deleteاستفاده کنید و لیستی از شبها را برای حذف تهیه کنید. اشکال این است که شما باید واکشی کنید یا بدانید که در جدول چیست. حاشیه نویسی@Deleteبرای حذف ورودی های خاص عالی است ، اما برای پاک کردن تمام ورودی ها از یک جدول کارآمد نیست.
@Query("DELETE FROM daily_sleep_quality_table")
fun clear()- با یک عملکرد
getTonight()یک@Queryاضافه کنید.SleepNightکه توسطgetTonight()قابل بازگشت است ، برگردانید تا عملکرد بتواند موردی را که جدول خالی است ، کنترل کند. (جدول در ابتدا خالی است و پس از پاک شدن داده ها.)
برای دریافت "امشب" از پایگاه داده ، یک پرس و جو SQLITE بنویسید که اولین عنصر لیستی از نتایج سفارش داده شده توسطnightIdرا به ترتیب نزولی باز می گرداند. برای بازگشت تنها یک عنصرLIMIT 1استفاده کنید.
@Query("SELECT * FROM daily_sleep_quality_table ORDER BY nightId DESC LIMIT 1")
fun getTonight(): SleepNight?- یک عملکرد
@QuerygetAllNights()اضافه کنید:
- از پرس و جو SQLITE بخواهید تمام ستون ها را از
daily_sleep_quality_tableبازگرداند ، که به ترتیب نزولی سفارش داده شده است. -
getAllNights()لیستی از اشخاصSleepNightبه عنوانLiveDataبرگردانید.RoomاینLiveDataرا برای شما به روز می کند ، این بدان معنی است که شما فقط باید یک بار صریح داده ها را دریافت کنید. - ممکن است شما نیاز به وارد کردن
LiveDataازandroidx.lifecycle.LiveDataداشته باشید.
@Query("SELECT * FROM daily_sleep_quality_table ORDER BY nightId DESC")
fun getAllNights(): LiveData<List<SleepNight>>- اگرچه هیچ گونه تغییر قابل مشاهده ای را مشاهده نخواهید کرد ، برنامه خود را اجرا کنید تا مطمئن شوید که هیچ خطایی ندارد.
در این کار ، شما یک پایگاه داده Room ایجاد می کنید که از Entity و DAO که در کار قبلی ایجاد کرده اید استفاده می کند.
شما باید یک کلاس نگهدارنده پایگاه داده انتزاعی ایجاد کنید ، حاشیه نویسی با @Database . این کلاس دارای یک روش است که در صورت وجود بانک اطلاعاتی ، نمونه ای از پایگاه داده را ایجاد می کند ، یا مرجع را به یک پایگاه داده موجود باز می گرداند.
گرفتن یک پایگاه داده Room کمی درگیر است ، بنابراین در اینجا روند کلی قبل از شروع با کد وجود دارد:
- یک کلاس
public abstractایجاد کنید کهextends RoomDatabase. این کلاس به عنوان دارنده بانک اطلاعاتی عمل می کند. کلاس انتزاعی است ، زیراRoomپیاده سازی را برای شما ایجاد می کند. - کلاس را با
@Databaseحاشیه نویسی کنید. در آرگومان ، اشخاص را برای پایگاه داده اعلام کرده و شماره نسخه را تنظیم کنید. - در داخل یک شی
companion، یک روش انتزاعی یا خاصیتی را تعریف کنید که یکSleepDatabaseDaoبرمی گرداند.Roomبدن را برای شما ایجاد می کند. - شما فقط به یک نمونه از پایگاه داده
Roomبرای کل برنامه نیاز دارید ، بنابراینRoomDatabaseبه یک مجرد تبدیل کنید. - از سازنده پایگاه داده
Roomاستفاده کنید تا پایگاه داده ایجاد کنید در صورت عدم وجود بانک اطلاعاتی. در غیر این صورت ، پایگاه داده موجود را برگردانید.
مرحله 1: پایگاه داده را ایجاد کنید
- در بسته
database،SleepDatabase.ktباز کنید. - در پرونده ، یک کلاس
abstractبه نامSleepDatabaseایجاد کنید کهRoomDatabaseگسترش می دهد.
کلاس را با@Databaseحاشیه نویسی کنید.
@Database()
abstract class SleepDatabase : RoomDatabase() {}- خطایی برای اشخاص گمشده و پارامترهای نسخه مشاهده خواهید کرد. حاشیه نویسی
@Databaseبه چندین استدلال نیاز دارد تاRoomبتواند پایگاه داده را بسازد.
-
SleepNightبه عنوان تنها مورد با لیستentitiesتهیه کنید. -
versionرا به صورت1تنظیم کنید . هر زمان که طرح را تغییر دهید ، باید شماره نسخه را افزایش دهید. -
exportSchemaبهfalseتنظیم کنید ، تا از نسخه پشتیبان تهیه نسخه Schema استفاده نکنید.
entities = [SleepNight::class], version = 1, exportSchema = false- این بانک اطلاعاتی باید در مورد DAO اطلاع داشته باشد. در داخل بدن کلاس ، یک مقدار انتزاعی را اعلام کنید که
SleepDatabaseDaoبرمی گرداند. شما می توانید چندین DAO داشته باشید.
abstract val sleepDatabaseDao: SleepDatabaseDao- در زیر آن ، یک شی
companionرا تعریف کنید. شیء همراه به مشتریان این امکان را می دهد تا بدون فوری کلاس ، به روشهای ایجاد یا گرفتن پایگاه داده دسترسی پیدا کنند. از آنجا که تنها هدف از این کلاس ارائه یک بانک اطلاعاتی است ، هیچ دلیلی برای فوری آن وجود ندارد.
companion object {}- در داخل شیء
companion، یک نمونه متغیر قابل تهی خصوصیINSTANCEبرای پایگاه داده اعلام کرده و آن را بهnullتنظیم کنید. متغیرINSTANCE، پس از ایجاد یک ، به پایگاه داده مراجعه می کند. این به شما کمک می کند تا به طور مکرر از اتصالات به پایگاه داده جلوگیری کنید که گران است.
نمونه INSTANCE با @Volatile . مقدار یک متغیر فرار هرگز ذخیره نمی شود و همه می نویسد و می خواند و از حافظه اصلی و از طریق حافظه اصلی انجام می شود. این به اطمینان حاصل می شود که مقدار INSTANCE همیشه به روز است و برای همه موضوعات اجرا یکسان است. این بدان معناست که تغییرات ایجاد شده توسط یک موضوع به INSTANCE بلافاصله برای همه موضوعات دیگر قابل مشاهده است ، و شما شرایطی را پیدا نمی کنید که مثلاً دو موضوع هر یک از یکسان را در یک حافظه نهان به روز کنید ، که این امر باعث ایجاد مشکل می شود.
@Volatile
private var INSTANCE: SleepDatabase? = null- در زیر
INSTANCE، هنوز هم در داخل شیءcompanion، یک روشgetInstance()را با یک پارامترContextکه سازنده پایگاه داده به آن نیاز دارد تعریف کنید. یک نوعSleepDatabaseبرگردانید. خطایی را مشاهده خواهید کرد زیراgetInstance()هنوز هیچ چیزی را برمی گرداند.
fun getInstance(context: Context): SleepDatabase {}- در داخل
getInstance()، یک بلوکsynchronized{}اضافه کنید. درthisعبور کنید تا بتوانید به متن دسترسی پیدا کنید.
موضوعات متعدد به طور بالقوه می توانند یک نمونه بانک اطلاعاتی را به طور همزمان درخواست کنند ، و در نتیجه دو پایگاه داده به جای یک. این مشکل به احتمال زیاد در این برنامه نمونه اتفاق نمی افتد ، اما برای یک برنامه پیچیده تر امکان پذیر است. بسته بندی کد برای به دست آوردن بانکsynchronizedبه این معنی است که فقط یک موضوع اجرای در یک زمان می تواند این بلوک از کد را وارد کند ، که باعث می شود پایگاه داده فقط یک بار اولیه شود.
synchronized(this) {}- در داخل بلوک هماهنگ شده ، مقدار فعلی
INSTANCEرا در یکinstanceمتغیر محلی کپی کنید. این برای استفاده از بازیگران هوشمند است که فقط در دسترس متغیرهای محلی است.
var instance = INSTANCE- در داخل بلوک
synchronized،return instanceدر انتهای بلوکsynchronized. خطای عدم تطابق نوع بازگشت را نادیده بگیرید. پس از اتمام کار ، هرگز تهی نخواهید کرد.
return instance- بالاتر از بیانیه
return، یک عبارتifرا اضافه کنید تا بررسی کنید که آیاinstanceتهی است ، یعنی هنوز پایگاه داده ای وجود ندارد.
if (instance == null) {}- اگر
instancenullاست ، برای تهیه یک پایگاه داده از سازنده پایگاه داده استفاده کنید. در بدنه بیانیهif، repokeRoom.databaseBuilderو زمینه ای را که در آن عبور کرده اید ، کلاس پایگاه داده و نامی برای بانک اطلاعاتی ،sleep_history_databaseتهیه کنید. برای رفع خطا ، باید در مراحل زیر یک استراتژی مهاجرت اضافه کرده وbuild().
instance = Room.databaseBuilder(
context.applicationContext,
SleepDatabase::class.java,
"sleep_history_database")- استراتژی مهاجرت مورد نیاز را به سازنده اضافه کنید. استفاده از
.fallbackToDestructiveMigration().
به طور معمول ، شما باید یک شیء مهاجرت را با یک استراتژی مهاجرت برای زمان تغییر طرح ارائه دهید. یک شیء مهاجرت یک شیء است که چگونه شما همه ردیف ها را با طرح قدیمی می گیرید و آنها را در طرح جدید به ردیف تبدیل می کنید ، به طوری که هیچ داده ای از بین نمی رود. مهاجرت فراتر از محدوده این CodeLab است. یک راه حل ساده نابودی و بازسازی بانک اطلاعاتی است ، به این معنی که داده ها از بین می روند.
.fallbackToDestructiveMigration()- سرانجام ، تماس بگیرید
.build().
.build()- به عنوان
INSTANCE = instanceبه عنوان مرحله آخر در بیانیهifاختصاص دهید.
INSTANCE = instance- کد نهایی شما باید به این شکل باشد:
@Database(entities = [SleepNight::class], version = 1, exportSchema = false)
abstract class SleepDatabase : RoomDatabase() {
abstract val sleepDatabaseDao: SleepDatabaseDao
companion object {
@Volatile
private var INSTANCE: SleepDatabase? = null
fun getInstance(context: Context): SleepDatabase {
synchronized(this) {
var instance = INSTANCE
if (instance == null) {
instance = Room.databaseBuilder(
context.applicationContext,
SleepDatabase::class.java,
"sleep_history_database"
)
.fallbackToDestructiveMigration()
.build()
INSTANCE = instance
}
return instance
}
}
}
}- کد خود را بسازید و اجرا کنید.
شما اکنون تمام بلوک های ساختمانی را برای کار با پایگاه داده Room خود دارید. این کد کامپایل و اجرا می شود ، اما شما هیچ راهی برای گفتن اینکه آیا واقعاً کار می کند ، ندارید. بنابراین ، این زمان خوبی برای اضافه کردن برخی از تست های اساسی است.
مرحله 2: SleepDatabase را آزمایش کنید
در این مرحله ، شما تست هایی را برای تأیید اینکه پایگاه داده شما کار می کند ، انجام داده اید. این به اطمینان حاصل می شود که پایگاه داده قبل از ساختن آن کار کند. تست های ارائه شده اساسی هستند. برای یک برنامه تولید ، شما تمام کارکردها و نمایش داده ها را در تمام DAO ها انجام می دهید.
برنامه استارت شامل یک پوشه AndroidTest است. این پوشه AndroidTest شامل تست های واحد است که شامل ابزار دقیق Android است ، این یک روش جالب برای گفتن است که آزمایشات به چارچوب Android نیاز دارند ، بنابراین شما باید آزمایشات را روی یک دستگاه فیزیکی یا مجازی اجرا کنید. البته ، شما همچنین می توانید تست های واحد خالص را که شامل چارچوب Android نیست ، ایجاد و اجرا کنید.
- در Android Studio ، در پوشه AndroidTest ، پرونده SleepDatabasetest را باز کنید.
- برای نادیده گرفتن کد ، تمام کد اظهار نظر را انتخاب کرده و میانبر
Cmd+/یاControl+/صفحه کلید را فشار دهید. - به پرونده نگاهی بیندازید.
در اینجا سریع کد آزمایش وجود دارد ، زیرا این یک قطعه دیگر از کد است که می توانید از آن استفاده کنید:
-
SleepDabaseTestیک کلاس تست است . - حاشیه نویسی
@RunWithRunner Test را مشخص می کند ، این برنامه ای است که تست ها را تنظیم و اجرا می کند. - در حین راه اندازی ، عملکرد حاشیه نویسی با
@Beforeاجرا می شود ، و باSleepDatabaseDaoیکSleepDatabaseدر حافظه ایجاد می کند. "در حافظه" به این معنی است که این پایگاه داده در سیستم پرونده ذخیره نمی شود و پس از اجرای تست ها حذف می شود. - همچنین هنگام ساختن بانک اطلاعاتی در حافظه ، کد یک روش خاص تست را ،
allowMainThreadQueriesمی نامد. به طور پیش فرض ، اگر سعی می کنید نمایش داده شد را روی موضوع اصلی اجرا کنید ، خطایی دریافت می کنید. این روش به شما امکان می دهد تست ها را روی موضوع اصلی اجرا کنید ، که فقط باید در حین آزمایش انجام دهید. - در یک روش آزمایشی که با
@Testحاشیه نویسی شده است ، شما یکSleepNightایجاد می کنید ، درج و بازیابی می کنید و ادعا می کنید که آنها یکسان هستند. اگر مشکلی پیش آمد ، یک استثنا را پرتاب کنید. در یک تست واقعی ، شما چندین@Testخواهید داشت روش ها - هنگام انجام آزمایش ، عملکردی که با
@Afterحاشیه نویسی شده است برای بستن پایگاه داده اجرا می شود.
- بر روی پرونده تست در صفحه پروژه راست کلیک کرده و اجرای "SleepDatabasetest" را انتخاب کنید.
- پس از انجام آزمایشات ، در صفحه Sleepdatabasetest که تمام آزمایشات گذرانده اند ، تأیید کنید.

از آنجا که تمام تست ها گذشت ، شما اکنون چندین چیز را می دانید:
- بانک اطلاعاتی به درستی ایجاد می شود.
- می توانید یک
SleepNightدر پایگاه داده وارد کنید. - می توانید شب
SleepNightبرگردانید. -
SleepNightارزش صحیحی برای کیفیت دارد.
پروژه استودیوی Android: TrackMysLeepQualityRoomAndTesting
هنگام آزمایش یک پایگاه داده ، باید تمام روشهای تعریف شده در DAO را اعمال کنید. برای تکمیل آزمایش ، تست ها را اضافه و انجام دهید تا روشهای دیگر DAO را انجام دهید.
- جداول خود را به عنوان کلاسهای داده حاشیه نویسی با
@Entityتعریف کنید. ویژگی های حاشیه نویسی با@ColumnInfoرا به عنوان ستون در جداول تعریف کنید. - یک شی دسترسی به داده (DAO) را به عنوان رابط حاشیه ای با
@Daoتعریف کنید. DAO توابع Kotlin را به نمایش داده های پایگاه داده نقشه می کند. - برای تعریف
@Insert،@Deleteو@Updateاز حاشیه نویسی استفاده کنید. - از حاشیه نویسی
@Queryبا یک رشته پرس و جو SQLITE به عنوان یک پارامتر برای هر پرس و جو دیگر استفاده کنید. - یک کلاس انتزاعی ایجاد کنید که دارای یک تابع
getInstance()باشد که یک پایگاه داده را برمی گرداند. - برای آزمایش اینکه پایگاه داده و DAO همانطور که انتظار می رود کار می کنند ، از تست های ابزار استفاده کنید. می توانید از تست های ارائه شده به عنوان الگوی استفاده کنید.
دوره بی ادبی:
اسناد توسعه دهنده اندرویدی:
-
RoomDatabase -
Database(حاشیه نویسی) - می توانید از نمایش داده های خام با
Roomاستفاده کنید -
Roomdatabase.Builder - آموزش تست
- کلاس
SQLiteDatabase -
Dao - کتابخانه توری
Room
سایر مستندات و مقالات:
این بخش، تکالیف احتمالی را برای دانشآموزانی که در این آزمایشگاه کد به عنوان بخشی از دورهای که توسط یک مربی هدایت میشود، کار میکنند، فهرست میکند. این وظیفه مربی است که موارد زیر را انجام دهد:
- در صورت نیاز تکالیف را تعیین کنید.
- نحوه ارسال تکالیف را با دانش آموزان در میان بگذارید.
- تکالیف را نمره دهید.
مربیان میتوانند از این پیشنهادات به اندازهای که میخواهند استفاده کنند، و باید با خیال راحت هر تکلیف دیگری را که فکر میکنند مناسب است، محول کنند.
اگر به تنهایی از طریق این کدها کار می کنید، از این تکالیف برای آزمایش دانش خود استفاده کنید.
به این س questions الات پاسخ دهید
سوال 1
چگونه نشان می دهید که یک کلاس نمایانگر یک موجودیت برای ذخیره در یک پایگاه داده Room است؟
- کلاس را توسعه دهید تا
DatabaseEntityگسترش دهد. - کلاس را با
@Entityحاشیه نویسی کنید. - کلاس را با
@Databaseحاشیه نویسی کنید. - کلاس را
RoomEntityگسترش دهید و همچنین کلاس را با@Roomحاشیه نویسی کنید.
سوال 2
DAO (شی دسترسی به داده) رابط کاربری است که Room برای نقشه برداری توابع کوتلین به نمایش داده های پایگاه داده استفاده می کند.
چگونه نشان می دهید که یک رابط کاربری DAO را برای یک پایگاه داده Room نشان می دهد؟
- رابط
RoomDAOرا گسترش دهید. - رابط را گسترش دهید
EntityDao، سپس روشDaoConnection()را پیاده سازی کنید. - رابط کاربری را با
@Daoحاشیه نویسی کنید. - رابط کاربری را با
@RoomConnectionحاشیه نویسی کنید.
سوال 3
کدام یک از گفته های زیر در مورد پایگاه داده Room صادق است؟ همه موارد کاربردی را انتخاب کنید.
- می توانید جداول را برای یک پایگاه داده
Roomبه عنوان کلاسهای داده حاشیه نویسی تعریف کنید. - اگر
LiveDataاز یک پرس و جو برگردانید ، در صورت تغییرLiveData،RoomLiveDataرا برای شما به روز می کند. - هر پایگاه داده
Roomباید یک و تنها یک دائو داشته باشد. - برای شناسایی یک کلاس به عنوان یک پایگاه داده
Room، آن را به زیر کلاسRoomDatabaseتبدیل کرده و آن را با@Databaseحاشیه نویسی کنید.
سوال 4
از کدام یک از حاشیه های زیر می توانید در رابط @Dao خود استفاده کنید؟ همه موارد کاربردی را انتخاب کنید.
-
@Get -
@Update -
@Insert -
@Query
سوال 5
چگونه می توانید تأیید کنید که پایگاه داده شما در حال کار است؟ همه موارد کاربردی را انتخاب کنید.
- تست های سازنده را بنویسید.
- نوشتن و اجرای برنامه را ادامه دهید تا زمانی که داده ها را نشان دهد.
- تماس ها را به روش های موجود در رابط DAO با تماس با روشهای معادل در کلاس
Entityجایگزین کنید. - عملکرد
verifyDatabase()ارائه شده توسط کتابخانهRoomرا اجرا کنید.
شروع به درس بعدی:
برای پیوند به سایر کدهای این دوره، به صفحه فرود کد لبههای کد پایه Android Kotlin Fundamentals مراجعه کنید.